Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Axes min/max are updated but charts are not updated to the new range #533

Closed
BBOYGF opened this issue Jul 13, 2022 · 7 comments
Closed

Axes min/max are updated but charts are not updated to the new range #533

BBOYGF opened this issue Jul 13, 2022 · 7 comments

Comments

@BBOYGF
Copy link

BBOYGF commented Jul 13, 2022

Describe the bug
我在用这个开源软件它非常棒,速度非常快但是我遇到一个问题。我在用DefaultNumericAxis类作为横坐标,但是当横坐标更新后我发现图并没有更新,我看到源码中作者是否忘记取更新缓存(调用AbstractAxisParameter 类的updateCachedVariables 方法)希望作者看到以后能修复这个BUG,谢谢祝您天天开心。

I'm using this open source software and it's great, it's really fast but I ran into a problem. I'm using DefaultNumericAxis as the abscissa, but when the abscissa is updated I find that the graph is not updated, I see whether the author forgot to take the update cache in the source code (call the AbstractAxisParameter class updateCachedVariables method). I hope the author can fix this BUG after reading it. Thank you and wish you a happy day.

    /**
     * The value for the upper bound of this axis, ie max value. This is automatically set if auto ranging is on.
     */
    protected final transient DoubleProperty maxProp = new SimpleDoubleProperty(this, "upperBound", DEFAULT_MAX_RANGE) {
        @Override
        public void set(final double newValue) {
            final double oldValue = get();
            if (oldValue != newValue) {
                super.set(newValue);
                updateCachedVariables(); // 我认为需要修改的地方 What I think needs to be changed
                invokeListener(new AxisChangeEvent(AbstractAxisParameter.this));
            }
        }
    };

    /**
     * The value for the lower bound of this axis, ie min value. This is automatically set if auto ranging is on.
     */
    protected final transient DoubleProperty minProp = new SimpleDoubleProperty(this, "lowerBound", DEFAULT_MIN_RANGE) {
        @Override
        public void set(final double newValue) {
            final double oldValue = get();
            if (oldValue != newValue) {
                super.set(newValue);
                updateCachedVariables(); // 我认为需要修改的地方 What I think needs to be changed
                invokeListener(new AxisChangeEvent(AbstractAxisParameter.this));
            }
        }
    };

Environment:

  • win10
  • Java version:16
  • JavaFx version: 17
  • ChartFx version: [master, chartfx-chart:11.2.5]
@BBOYGF BBOYGF added the bug label Jul 13, 2022
@BBOYGF BBOYGF changed the title 坐标轴更新了但是图表没有更新问题 坐标轴更新了但是图表没有更新问题 The axes are updated but the charts are not Jul 13, 2022
@wirew0rm
Copy link
Member

Hey, thanks for the feedback on using our library. Could you provide a minimal sample which reproduces your problem?
The updateCachedVariables() function is called in the layouting step which is triggered by the AxisChangeEvent emitted in the line below, so it should not be necessary here and there is probably some other problem.

@wirew0rm wirew0rm changed the title 坐标轴更新了但是图表没有更新问题 The axes are updated but the charts are not Axes min/max are updated but charts are not updated to the new range Jul 13, 2022
@BBOYGF
Copy link
Author

BBOYGF commented Jul 13, 2022

谢谢您的回复,这是我提出问题的原因,你可以运行一下下面的代码会发现X轴更新了但是图没有更新,期待你的回复谢谢!
Thank you for your reply, this is the reason why I raised the question. You can run the following code and find that the X-axis is updated but the graph is not. Looking forward to your reply, thank you!

import de.gsi.chart.XYChart;
import de.gsi.chart.axes.spi.DefaultNumericAxis;
import de.gsi.chart.renderer.spi.ErrorDataSetRenderer;
import de.gsi.dataset.spi.DoubleDataSet;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 *
 * @author guofan
 * @date 2022/7/13
 */
public class ChartFxSample extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        DefaultNumericAxis xAxis = new DefaultNumericAxis();
        xAxis.setName("X");
        xAxis.setAutoRanging(false);
        DefaultNumericAxis yAxis = new DefaultNumericAxis();
        yAxis.setName("Y");
        XYChart chart = new XYChart(xAxis, yAxis);
        DoubleDataSet dataSet = new DoubleDataSet("data");
        double[] xValues = new double[1000];
        double[] yValues = new double[1000];
        for (int i = 0; i < 1000; i++) {
            xValues[i] = i;
            yValues[i] = Math.sin(i / 10);
        }
        dataSet.set(xValues, yValues);
        ErrorDataSetRenderer renderer = new ErrorDataSetRenderer();
        renderer.getDatasets().add(dataSet);
        chart.getRenderers().add(renderer);
        xAxis.setMin(-500);
        xAxis.setMax(1500);
        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(chart);
        Button updateXAxisButton = new Button("updateXAxis");
        updateXAxisButton.setOnAction(event -> {
            xAxis.setMin(0);
        });
        borderPane.setBottom(updateXAxisButton);
        Scene scene = new Scene(borderPane);
        primaryStage.setScene(scene);
        primaryStage.setWidth(600);
        primaryStage.setHeight(400);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

@wirew0rm
Copy link
Member

Ok, I can reproduce the issue, thanks for the fast reply. We usually have fast updating data or use interactive rescaling where the chart lagging one update behind the axes it not really noticeable.
The core problem is, that the axes and charts are both rendered in the layoutChildren step of javafx and the plot is rendered before the axes and so it does not get updated before. Updating the cache on each change kind of defeats its purpose, so we will have to fix the root cause of this.

Meanwhile as a workaround you can either use a custom axis with the changes you proposed above or use this snippet in your app to force a second redraw:

xAxis.setMin(0);
FXUtils.waitForFxTicks(scene, 1);
chart.requestLayout();

I'm actually in the process of restructuring the layouting and rendering code for the 11.3 release where i hope to improve problems like this, see #527 and #529 .

@BBOYGF
Copy link
Author

BBOYGF commented Jul 13, 2022

谢谢你的回复,但是没有解决我的问题,我的解决方案是这样的。
Thanks for your reply, but it doesn't solve my problem. My solution is as follows.

import de.gsi.chart.axes.spi.DefaultNumericAxis;

/**
 * 可更手动更新的轴
 *
 * @author guofan
 * @date 2022/7/13
 */
public class UpdateNumericAxis extends DefaultNumericAxis {
    /**
     * 更新轴缓存
     */
    public void updateAxisCache() {
        updateCachedVariables();
    }
}
import de.gsi.chart.XYChart;
import de.gsi.chart.axes.spi.DefaultNumericAxis;
import de.gsi.chart.renderer.spi.ErrorDataSetRenderer;
import de.gsi.dataset.spi.DoubleDataSet;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 *
 * @author guofan
 * @date 2022/7/13
 */
public class ChartFxSample extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        UpdateNumericAxis xAxis = new UpdateNumericAxis();
        xAxis.setName("X");
        xAxis.setAutoRanging(false);
        // 添加更新缓存  Add update cache
        xAxis.minProperty().addListener((observable, oldValue, newValue) -> xAxis.updateAxisCache());

        DefaultNumericAxis yAxis = new DefaultNumericAxis();
        yAxis.setName("Y");
        XYChart chart = new XYChart(xAxis, yAxis);
        DoubleDataSet dataSet = new DoubleDataSet("data");
        double[] xValues = new double[1000];
        double[] yValues = new double[1000];
        for (int i = 0; i < 1000; i++) {
            xValues[i] = i;
            yValues[i] = Math.sin(i / 10);
        }
        dataSet.set(xValues, yValues);
        ErrorDataSetRenderer renderer = new ErrorDataSetRenderer();
        renderer.getDatasets().add(dataSet);
        chart.getRenderers().add(renderer);
        xAxis.setMin(-500);
        xAxis.setMax(1500);
        BorderPane borderPane = new BorderPane();
        borderPane.setCenter(chart);
        Button updateXAxisButton = new Button("updateXAxis");
        updateXAxisButton.setOnAction(event -> {
            xAxis.setMin(0);
        });
        Scene scene = new Scene(borderPane);
        borderPane.setBottom(updateXAxisButton);
        primaryStage.setScene(scene);
        primaryStage.setWidth(600);
        primaryStage.setHeight(400);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

@karlduderstadt
Copy link

@guofan2019 thanks for reporting this issue and sharing your solution. We also noticed this behavior for a long time and assumed it was a mistake in our implementation. We added an extra layout() call after essentially all plot changes to solve the problem, but I think your solution might be more elegant better.

We also exclusively use chartfx for fixed charts that don't update in real-time, so this explains why we have also see this problem. I assume many others use this awesome library in this way, so it would be really great if this was fixed in the library.

@ichaus-we
Copy link
Contributor

...
Meanwhile as a workaround you can either use a custom axis with the changes you proposed above or use this snippet in your app to force a second redraw:

xAxis.setMin(0);
FXUtils.waitForFxTicks(scene, 1);
chart.requestLayout();

...

I too came across this issue and wanted to add my findings.
The work-around will not work, if you already are on the Fx Application Thread, because in that case the chartfx library makes a call to Platform.requestNextPulse(). But this method returns immediatly, not waiting for the pulse to happen and thus chart.requestLayout() is called too early.

@wirew0rm
Copy link
Member

wirew0rm commented Aug 9, 2023

solved by #592, which will be included in the major release coming soon. Sorry for having to live with the workarounds for so long, feel free to reopen if the problems persist on main or in the upcoming 11.3 release.

@wirew0rm wirew0rm closed this as completed Aug 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants