JavaFX LineChart具有65000个数据点时的性能问题

它需要JavaFX 15分钟来构建描述的LineChart,它不适用于我的任务。

使用良好的旧Swing和jFreeChart的类似实现需要1.5秒来构建图表。

但是我仍然想要实现一个JavaFX。

这是我的代码:

public class FXMLController implements Initializable {

@FXML
private Label statusbar;
@FXML
public LineChart lineChart;
@FXML
public Button connect;
@FXML
public MenuItem options;
@FXML
public NumberAxis xAxis;
@FXML
NumberAxis yAxis;

@FXML
private void connect(ActionEvent event) {

}
public static FileChooser fileChooser = new FileChooser();
public static String path;
public static XYChart.Series<Integer, Integer> dataSeries = new XYChart.Series<Integer, Integer>();
public static int y = 0;
public static XYChart.Data<Integer, Integer> data;


@FXML
private void open(ActionEvent event) {
    fileChooser.setTitle("Open Resource File");
    fileChooser.getExtensionFilters().addAll(
            new ExtensionFilter("Text Files", "*.txt"),
            new ExtensionFilter("Image Files", "*.png", "*.jpg", "*.gif"),
            new ExtensionFilter("Audio Files", "*.wav", "*.mp3", "*.aac"),
            new ExtensionFilter("All Files", "*.*"));
    File selectedFile = fileChooser.showOpenDialog(new Stage());
    if (selectedFile != null) {
        path = selectedFile.getAbsolutePath();
        System.out.println(path);
        try {
            ReadingFromFile.readFile(path);

        } catch (IOException ex) {
            Logger.getLogger(FXMLController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}

@FXML
private void close(ActionEvent event) {

}

@FXML
private void getconnect(ActionEvent event) {

}

@Override
public void initialize(URL url, ResourceBundle rb) {
    xAxis.setLabel("Tick");
    xAxis.setTickUnit(100);
    yAxis.setLabel("Signal");
    xAxis.setForceZeroInRange(false);
    lineChart.setLegendVisible(false);
    lineChart.setCreateSymbols(false);
    lineChart.setAnimated(false);
    lineChart.getData().add(dataSeries);
  }
}

并从文件中读取:

public class ReadingFromFile extends FXMLController {

public static String s = null;
public static String[] str;
public static int parseInt;

public static void readFile(String filename)
        throws IOException {

    BufferedReader br = new BufferedReader(new FileReader(filename));
    try {
        StringBuilder sb = new StringBuilder();
        String line = br.readLine();

        while (line != null) {
            sb.append(line);
            sb.append(System.lineSeparator());
            line = br.readLine();

            System.out.println(line);
            try {
                str = line.split(" ");
                for (int i = 0; i < str.length; i = i + 2) {
                    s = str[i + 1] + str[i];
                    parseInt = Integer.parseInt(s, 16);
                    javafx.application.Platform.runLater(new Runnable() {
                        @Override
                        public void run() {

                            data = new XYChart.Data<Integer, Integer>(y, parseInt);
                            //data.setNode(new HoveredThresholdNode(0, second, ""));
                            dataSeries.getData().add(data);
                            y++;
                        }

                    });
                }
            } catch (java.lang.NullPointerException ex) {
                System.out.println("тут ноль!!!");

            }

        }

    } finally {

        br.close();
    }

}

}

我遇到过类似的问题,每隔几秒就为LineChart添加100,000点。 我们使用Ramer-Douglas-Peucker算法解决了这个问题,这可以减少线路中的点数,而无需用户注意。 我在LGPL许可下的JTS拓扑套件中找到了现成的实现。

这是我的测试代码。

public class ChartUpdate extends Application {

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

    @Override
    public void start(Stage stage) {

        NumberAxis xAxis = new NumberAxis(0, 50_000, 5000);
        xAxis.setAutoRanging(false);
        NumberAxis yAxis = new NumberAxis(-1, 1, 25);
        yAxis.setAutoRanging(false);
        LineChart<Number, Number> graph = new LineChart<>(xAxis, yAxis);
        graph.setAnimated(false);
        graph.setCreateSymbols(false);
        graph.setLegendVisible(false);
        Series<Number, Number> series = new Series<>();
        stage.setScene(new Scene(graph));

        GeometryFactory gf = new GeometryFactory();

        long t0 = System.nanoTime();
        Coordinate[] coordinates = new Coordinate[100_000];
        for (int i = 0; i < coordinates.length; i++) {
            coordinates[i] = new Coordinate(i, Math.sin(Math.toRadians(i / 100)));
        }
        Geometry geom = new LineString(new CoordinateArraySequence(coordinates), gf);
        Geometry simplified = DouglasPeuckerSimplifier.simplify(geom, 0.00001);
        List<Data<Number, Number>> update = new ArrayList<Data<Number, Number>>();
        for (Coordinate each : simplified.getCoordinates()) {
            update.add(new Data<>(each.x, each.y));
        }
        long t1 = System.nanoTime();

        System.out.println(String.format("Reduces points from %d to %d in %.1f ms", coordinates.length, update.size(),
                (t1 - t0) / 1e6));
        ObservableList<Data<Number, Number>> list = FXCollections.observableArrayList(update);
        series.setData(list);
        graph.getData().add(series);

        stage.show();

    }
}

Ramer-Douglas-Peucker不必要的复杂,即使采用更快的下采样策略,仅靠这一点也不足以获得我们所需的性能。 在这里查看我的答案以获得更完整的解决方案 这为我实现了40,000左右的实时更新。

链接地址: http://www.djcxy.com/p/25163.html

上一篇: Performance issue with JavaFX LineChart with 65000 data points

下一篇: How to render heatmap.js on an image?