我想使用JavaFX绘制LineChart。如何使用Array数据集进行绘图,这意味着我有两个相等长度的X和Y双精度数组。我想将它们用作绘图的数据集。
先谢谢。
答案 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);