使用数组的JavaFX折线图

时间:2018-06-15 05:12:10

标签: javafx linechart

我想使用JavaFX绘制LineChart。如何使用Array数据集进行绘图,这意味着我有两个相等长度的X和Y双精度数组。我想将它们用作绘图的数据集。

先谢谢。

2 个答案:

答案 0 :(得分:1)

编辑:我的代码中有不必要的步骤。与向系列添加数据相比,性能的提高并非直接归因于Collection vs. ObservableList,而且在创建ObservableArrayList并直接用数据填充ObservableArrayList时,我可以获得相同的性能。

导致Christian Fries解决方案花费大量数据的时间更长的问题在XYChart.Series类中。如果您查看XYChart.Series的JavaFX中的源代码,它具有一个更改侦听器,该侦听器遍历所有数据,并在每次将数据添加到系列时激活。

总之,您可以从原始解决方案中删除1行,如以下代码所示,并获得相同的性能提升。但是,我将保留原件。

    // Create the graph
    LineChart<Number, Number> graph = new LineChart<Number, Number>(new NumberAxis(), new NumberAxis());
    
    // Create the list
    ObservableList<XYChart.Data<Number, Number>> list = FXCollections.observableArrayList();
    
    // Add all values from the array into the list
    for (int val : value)
        list.add(new XYChart.Data<Number, Number>(val,val));
    
    // create a series from the list
    XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>(list);
    
    // Add the series to the graph
    graph.getData().add(series);

我一直在寻找解决这个问题的方法,但是Christian Fries解决方案对我来说不起作用,因为我拥有大量数据,并且花了很长时间来绘制图形。

经过一些研究,我发现问题可能是由于JavaFX Series类的工作原理而引起的,并且每次向系列添加数据时,它实际上都必须重新评估所有数据的有效性,因为它使用了ObservableList在内部,因此添加的每个数据点都比上一个花费更长的时间。换句话说,指数时间复杂度绝对是可以避免的。

我发现一个更好的解决方案是创建JavaFX数据的集合,并将数据添加到此集合。完全填充后,可以将该集合转换为JavaFX系列,并像通常绘制系列一样绘制图表。请参见以下代码,其中数组名为“值”。

    // Create the graph
    LineChart<Number, Number> graph = new LineChart<Number, Number>(new NumberAxis(), new NumberAxis());
    
    // Create the collection
    Collection<XYChart.Data<Number, Number>> collection = new ArrayList<XYChart.Data<Number, Number>>();
    
    // Put all values from the array into the collection
    for (int val : value)
        collection.add(new XYChart.Data<Number, Number>(val,val));
    
    // Create the data using the collection
    ObservableList<XYChart.Data<Number, Number>> list = FXCollections.observableArrayList(collection);
    
    // create a series from the list
    XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>(list);
    
    // Add the series to the graph
    graph.getData().add(series);

虽然代码看起来比Christian Fries稍微复杂一些,但实际上在性能方面要高效得多。如果您不希望看到实际的性能差异,则可以运行以下代码,尽管我不建议这样做,因为方法2需要很长时间。另外,请记住,代码中的第二种方法具有指数的时间复杂度,因此数据越多,花费的时间差异就越大。

    import java.util.ArrayList;
    import java.util.Calendar;
    import java.util.Collection;
    
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.scene.Scene;
    import javafx.scene.chart.LineChart;
    import javafx.scene.chart.NumberAxis;
    import javafx.scene.chart.XYChart;
    import javafx.stage.Stage;
    
    public class GraphingImplementation  extends Application
    {
        @Override
        public void start(Stage stage)
        {
            // close the initial stage.
            stage.close();
            
            // The size of the array
            int seriesSize = 50000;
            
            // Build the graphs
            LineChart<Number, Number> graph1 = new LineChart<Number, Number>(new NumberAxis(), new NumberAxis());
            LineChart<Number, Number> graph2 = new LineChart<Number, Number>(new NumberAxis(), new NumberAxis());
            
            // Deactivate features that cause slow down
            graph1.setCreateSymbols(false);
            graph1.setAnimated(false);
            graph2.setCreateSymbols(false);
            graph2.setAnimated(false);
            
            // Create value array to graph.
            int value[] = new int[seriesSize];
            for(int i = 0; i<seriesSize; i++)
                value[i] = i;
            
            
            
            //**********************************************************
            // METHOD #1 - Creation of collection to populate series
            //**********************************************************
            // TIME COMPLEXITY - O{n}
            //**********************************************************
            // Mark the starting time of graphing method #1
            long startTime = Calendar.getInstance().getTimeInMillis();
            // Create the collection
            Collection<XYChart.Data<Number, Number>> collection = new ArrayList<XYChart.Data<Number, Number>>();
            // Add all values into the collection
            for (int val : value)
                collection.add(new XYChart.Data<Number, Number>(val,val));
            // Create the data using the collection
            ObservableList<XYChart.Data<Number, Number>> list = FXCollections.observableArrayList(collection);
            // create a series from the list
            XYChart.Series<Number, Number> series = new XYChart.Series<Number, Number>(list);
            // Add the series to the graph
            graph1.getData().add(series);
            // Mark the stopping time of graphing method #1
            long stopTime = Calendar.getInstance().getTimeInMillis();
            // Print the run time for method #1
            System.out.println((stopTime - startTime) + " Milliseconds");
            
            
            
            // build the first scene
            Scene scene1 = new Scene(graph1, 640, 480);
            // create and populate the first stage
            Stage stage1 = new Stage();
            stage1.setScene(scene1);
            // show the first stage
            stage1.show();
            
            
    
            
            //**********************************************************
            // METHOD #2 - Direct creation of a series
            //**********************************************************
            // TIME COMPLEXITY - O{n^2}
            //**********************************************************
            // Mark the starting time of graphing method #2
            startTime = Calendar.getInstance().getTimeInMillis();
            // Create the XYChart Series
            XYChart.Series<Number, Number> series2 = new XYChart.Series<Number, Number>();
            // add all values to the series
            for (long val : value)
                series2.getData().add(new XYChart.Data<Number, Number>(val, val));
            // add the series to the graph
            graph2.getData().add(series2);
            // Mark the stopping time of graphing method #2
            stopTime = Calendar.getInstance().getTimeInMillis();
            // Print the run time for method #2
            System.out.println((stopTime - startTime) + " Milliseconds");
            
            
            
            // build the second scene
            Scene scene2 = new Scene(graph2, 640, 480);
            // create and populate the second stage
            Stage stage2 = new Stage();
            stage2.setScene(scene2);
            // show the second stage
            stage2.show();
        }
        
        public static void main(String[] args)
        {
            launch(args);
        }
        
    }

此代码在终端中报告以下内容:

75毫秒

89896毫秒

因此,如您所见,方法1只需75毫秒,而方法2则需要近一分半钟。而且,您绘制的数据越多,#1的改进方法就越出色。

此外,请注意是否有任何重要意义。我正在使用Java / JavaFX 8。

答案 1 :(得分:0)

只需在循环中填写系列:

final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();

LineChart<Number,Number lineChart = new LineChart<Number,Number>(xAxis,yAxis);

XYChart.Series series = new XYChart.Series();
series.setName("data");
for(int i = 0; i<xArray.length; i++) {
    series.getData().add(new XYChart.Data(xArray[i], yArray[i]);
}
lineChart.getData().add(series);
相关问题