JavaFX图表自动缩放错误,数字较小 [英] JavaFX Chart Auto-Scaling Wrong with Low Numbers

查看:131
本文介绍了JavaFX图表自动缩放错误,数字较小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JavaFX构建StackedBarChart。随着新数据的出现,图表会发生变化。我正在用一个更新图表的按钮来模拟这个。

I'm using JavaFX to build a StackedBarChart. The chart will change as new data comes in. I'm simulating this with a button that updates the chart.

它基本上可以正常工作,但我注意到它的值很低(值小于~100),当我第一次更新图表时,Y轴标签似乎有些偏差:

It mostly works okay, but I noticed that with low values (values less than ~100), the Y-Axis labels seem a little off when I first update the chart:

Weirder仍然是,如果我更新图表一秒钟时间(或第三,第四......),Y轴的自动缩放远离:

Weirder still, if I update the chart a second time (or third, fourth...), the auto-scaling of the Y-Axis is way off:

如果我使用更大的值(值> ~1000) ),然后自动缩放工作正常。如果我停用图表动画,那么自动缩放工作正常。第一次更新图表时自动缩放工作正常,但之后没有。

If I use larger values (values > ~1000), then the auto-scaling works fine. If I deactivate the chart animation, then the auto-scaling works fine. The auto-scaling works fine the first time I update the chart, but not after that.

这是我正在使用的代码,它与代码完全相同来自 JavaFX教程。

Here's the code I'm using, which is pretty much identical to the code from this JavaFX tutorial.

import java.util.Arrays;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.StackedBarChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class StackedBarChartSample extends Application {

    final CategoryAxis xAxis = new CategoryAxis();
    final NumberAxis yAxis = new NumberAxis();
    final StackedBarChart<String, Number> sbc = new StackedBarChart<String, Number>(xAxis, yAxis);

    @Override
    public void start(Stage stage) {

        stage.setTitle("Bar Chart Sample");

        sbc.setAnimated(true); //change this to false and autoscaling works!


        Button button = new Button("update");
        button.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent arg0) {
                updateChart();
            }

        });

        VBox contentPane = new VBox();
        contentPane.getChildren().addAll(sbc, button);

        Scene scene = new Scene(contentPane, 800, 600);

        stage.setScene(scene);
        stage.show();
    }


    private void updateChart(){

        int m = 1; //change this to 100 and autoscaling works!


        xAxis.setCategories(FXCollections.<String>observableArrayList());
        sbc.getData().clear();

        final XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
        final XYChart.Series<String, Number> series2 = new XYChart.Series<String, Number>();

        series1.setName("ABC");
        series1.getData().add(new XYChart.Data<String, Number>("one", 25*m));
        series1.getData().add(new XYChart.Data<String, Number>("two", 20*m));
        series1.getData().add(new XYChart.Data<String, Number>("three", 10*m));

        series2.setName("XYZ");
        series2.getData().add(new XYChart.Data<String, Number>("one", 25*m));
        series2.getData().add(new XYChart.Data<String, Number>("two", 20*m));
        series2.getData().add(new XYChart.Data<String, Number>("three", 10*m));


        xAxis.setCategories(FXCollections.<String>observableArrayList(Arrays.asList("one", "two", "three")));
        sbc.getData().addAll(series1, series2);
    }

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

奖励问题:动画即使有效,显示每个堆叠条形图的2个额外部分,在动画完成时消失。有没有办法在动画期间摆脱那些额外的部分?

Bonus question: the animation, even when it works, shows 2 extra sections of each stacked bar, which disappear when the animation completes. Is there a way to get rid of those extra sections during the animation?

推荐答案

您正在使用图表,动画和以某种方式修改可观察列表似乎并不意味着要完成。好吧,我最初也是。我遇到过像这样的问题,其中包括ArrayIndexOutOfBounds Exceptions。简而言之:JavaFX图表的动画非常破碎,或者看起来如此。它似乎不可靠,因此当你直接修改列表时无法使用。

You are using the chart, the animation and the modification of the observable list in a way it seems it's not meant to be done. Well, so did I initially. I've run into problems like this, among them ArrayIndexOutOfBounds Exceptions. In short: the animation of the JavaFX charts is very broken, or so it appears. It seems to be unreliable and hence unusable when you directly modify the list.

我停止使用动画或修改列表,而是在每次更改时设置列表。这两种方法都解决了这个问题。

I stopped using the animation or modification of the list and instead set the list on every change. Either of these methods solved the problem.

使用sbc.setData()而不是sbc.getData()。clear()和sbc.getData()。addAll()修改示例。这有效,我。即动画仍然开启:

Modification of the example by using sbc.setData() instead of sbc.getData().clear() and sbc.getData().addAll(). This works, i. e. the animation is still on:

public class StackedBarChartSample extends Application {

    final CategoryAxis xAxis = new CategoryAxis();
    final NumberAxis yAxis = new NumberAxis();
    final StackedBarChart<String, Number> sbc = new StackedBarChart<String, Number>(xAxis, yAxis);

    Random rnd = new Random();

    @Override
    public void start(Stage stage) {

        stage.setTitle("Bar Chart Sample");

        sbc.setAnimated(true); //change this to false and autoscaling works!

        Button button = new Button("update");
        button.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent arg0) {
                updateChart();
            }

        });

        VBox contentPane = new VBox();
        contentPane.getChildren().addAll(sbc, button);

        Scene scene = new Scene(contentPane, 800, 600);

        stage.setScene(scene);
        stage.show();
    }


    private void updateChart(){

        int m = 1; //change this to 100 and autoscaling works!

        m = rnd.nextInt(100) + 1; // just some random value to see changes in the chart

        System.out.println( "m = " + m);

        final XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
        final XYChart.Series<String, Number> series2 = new XYChart.Series<String, Number>();

        series1.setName("ABC");
        series1.getData().add(new XYChart.Data<String, Number>("one", 25*m));
        series1.getData().add(new XYChart.Data<String, Number>("two", 20*m));
        series1.getData().add(new XYChart.Data<String, Number>("three", 10*m));

        series2.setName("XYZ");
        series2.getData().add(new XYChart.Data<String, Number>("one", 25*m));
        series2.getData().add(new XYChart.Data<String, Number>("two", 20*m));
        series2.getData().add(new XYChart.Data<String, Number>("three", 10*m));

        sbc.setData( FXCollections.observableArrayList(series1, series2));
    }

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

我为你的m添加了随机性以便查看更改在吧。

I added randomness for your m in order to see changes in the bars.

但真正的问题是你使用图表的方式。您不应该修改列表,而是应该修改列表项的数据。然后图表动画按预期工作,条形图随数据上升和下降。

But the real problem is the way you use the chart. You shouldn't modify the list, but instead you should modify the data of the list items. Then the chart animation works as expected, the bars rise and fall with the data.

带有创建(创建新图表列表)和修改(修改)的示例列表的数据,但不创建新列表)按钮:

Example with a "create" (creates new chart list) and "modify" (modifies the list's data, but doesn't create a new list) button:

public class StackedBarChartSample extends Application {

    final CategoryAxis xAxis = new CategoryAxis();
    final NumberAxis yAxis = new NumberAxis();
    final StackedBarChart<String, Number> sbc = new StackedBarChart<String, Number>(xAxis, yAxis);

    Random rnd = new Random();

    final XYChart.Series<String, Number> series1 = new XYChart.Series<String, Number>();
    final XYChart.Series<String, Number> series2 = new XYChart.Series<String, Number>();

    @Override
    public void start(Stage stage) {

        stage.setTitle("Bar Chart Sample");

        sbc.setAnimated(true); //change this to false and autoscaling works!

        Button createButton = new Button("Create");
        createButton.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent arg0) {
                createChartData();
            }

        });

        Button modifyButton = new Button("Modify");
        modifyButton.setOnAction(new EventHandler<ActionEvent>(){
            @Override
            public void handle(ActionEvent arg0) {
                modifyChartData();
            }

        });

        VBox contentPane = new VBox();
        contentPane.getChildren().addAll(sbc, createButton, modifyButton);

        Scene scene = new Scene(contentPane, 800, 600);

        stage.setScene(scene);
        stage.show();
    }


    private void createChartData(){

        int m = 1; //change this to 100 and autoscaling works!

        m = rnd.nextInt(100) + 1; // just some random value to see changes in the chart

        System.out.println( "m = " + m);

        series1.setName("ABC");
        series1.getData().add(new XYChart.Data<String, Number>("one", 25*m));
        series1.getData().add(new XYChart.Data<String, Number>("two", 20*m));
        series1.getData().add(new XYChart.Data<String, Number>("three", 10*m));

        series2.setName("XYZ");
        series2.getData().add(new XYChart.Data<String, Number>("one", 25*m));
        series2.getData().add(new XYChart.Data<String, Number>("two", 20*m));
        series2.getData().add(new XYChart.Data<String, Number>("three", 10*m));

        sbc.setData( FXCollections.observableArrayList(series1, series2));
    }

    private void modifyChartData() {

        int m = 1; //change this to 100 and autoscaling works!

        m = rnd.nextInt(100) + 1; // just some random value to see changes in the chart

        System.out.println( "m = " + m);

        for( XYChart.Data<String,Number> data: series1.getData()) {
            data.setYValue(rnd.nextInt(30) * m);
        }

        for( XYChart.Data<String,Number> data: series2.getData()) {
            data.setYValue(rnd.nextInt(30) * m);
        }


    }

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

这篇关于JavaFX图表自动缩放错误,数字较小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆