Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javafx 2 带有65000个数据点的JavaFX线形图的性能问题_Javafx 2_Javafx 8 - Fatal编程技术网

Javafx 2 带有65000个数据点的JavaFX线形图的性能问题

Javafx 2 带有65000个数据点的JavaFX线形图的性能问题,javafx-2,javafx-8,Javafx 2,Javafx 8,JavaFX需要15分钟来构建所描述的折线图,但该折线图不适用于我的任务 使用良好的旧Swing和jFreeChart的类似实现需要1.5秒来构建图表 但我仍然希望实现一个JavaFX 这是我的密码: public class FXMLController implements Initializable { @FXML private Label statusbar; @FXML public LineChart lineChart; @FXML public Button connect;

JavaFX需要15分钟来构建所描述的折线图,但该折线图不适用于我的任务

使用良好的旧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);
  }
}
公共类FXMLController实现可初始化{
@FXML
私有标签状态栏;
@FXML
公共线形图;
@FXML
公共按钮连接;
@FXML
公共菜单项选项;
@FXML
公共号码xis xAxis;
@FXML
数字轴yAxis;
@FXML
专用void connect(ActionEvent事件){
}
public static FileChooser FileChooser=新FileChooser();
公共静态字符串路径;
公共静态XYChart.Series dataSeries=新的XYChart.Series();
公共静态int y=0;
公共静态XYChart。数据;
@FXML
私有无效打开(ActionEvent事件){
setTitle(“打开的资源文件”);
fileChooser.getExtensionFilters().addAll(
新的ExtensionFilter(“文本文件”,“*.txt”),
新的ExtensionFilter(“图像文件”、“*.png”、“*.jpg”、“*.gif”),
新的扩展过滤器(“音频文件”、“*.wav”、“*.mp3”、“*.aac”),
新的扩展过滤器(“所有文件”,“*”);
File selectedFile=fileChooser.showOpenDialog(new Stage());
如果(selectedFile!=null){
path=selectedFile.getAbsolutePath();
System.out.println(路径);
试一试{
ReadingFromFile.readFile(路径);
}捕获(IOEX异常){
Logger.getLogger(FXMLController.class.getName()).log(Level.SEVERE,null,ex);
}
}
}
@FXML
私有无效关闭(ActionEvent事件){
}
@FXML
私有void getconnect(ActionEvent事件){
}
@凌驾
公共void初始化(URL、ResourceBundle rb){
xAxis.setLabel(“勾号”);
xAxis.settick单位(100);
yAxis.setLabel(“信号”);
xAxis.setForceZeroInRange(假);
线形图。setLegendVisible(假);
lineChart.setCreateSynumbles(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();
    }

}

}
public类ReadingFromFile扩展FXMLController{
公共静态字符串s=null;
公共静态字符串[]str;
公共静态int-parseInt;
公共静态void readFile(字符串文件名)
抛出IOException{
BufferedReader br=新的BufferedReader(新文件读取器(文件名));
试一试{
StringBuilder sb=新的StringBuilder();
String line=br.readLine();
while(行!=null){
某人附加(行);
sb.append(System.lineSeparator());
line=br.readLine();
系统输出打印项次(行);
试一试{
str=行分割(“”);
对于(int i=0;i
我也遇到了类似的问题,每几秒钟就在折线图上增加100000个点。我们使用解决它,这减少了线中的点数,而用户没有注意到。我在under LGPL许可证中找到了一个现成的实现

这是我的测试代码

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();

    }
}
公共类ChartUpdate扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公众假期开始(阶段){
NumberAxis xAxis=新的NumberAxis(0,50_000,5000);
xAxis.setAutoRanging(假);
NumberAxis-yAxis=新的NumberAxis(-1,1,25);
yAxis.setAutoRanging(假);
线形图=新线形图(xAxis,yAxis);
设置动画(假);
graph.setCreateSymbols(false);
graph.setLegendVisible(假);
系列=新系列();
舞台场景(新场景(图));
GeometryFactory gf=新的GeometryFactory();
long t0=System.nanoTime();
坐标[]坐标=新坐标[100_000];
对于(int i=0;i
Ramer Douglas Peucker不必要地复杂,即使采用更快的下采样策略,单凭这一点还不足以获得我们需要的性能。有关更完整的解决方案,请参见我的答案。这为我实现了真正的实时更新,数据集大约为40000个。

我最近也遇到了这个问题。下面是一个带注释的课堂示例。我还创建了一个JavaFX应用程序来测试输入的epsilon和GitHub上标记的数量

/**
*使用Douglas Peucker算法减少级数。
*
/**
 * Uses the Douglas Peucker algorithm for reducing the series.
 * Reference: https://rosettacode.org/wiki/Ramer-Douglas-Peucker_line_simplification#Java
 */
public class SeriesReducer {

  private double epsilon;

  /**
   * Filters the series. This assumes the data set is a map that uses the keys for a line chart
   * category axis and uses the values for a line chart number axis.
   * 
   * @param chartDataSet The map containing the chart data set
   */
  public Map<String, Integer> filter(Map<String, Integer> chartDataSet) {
    List<Entry<String, Integer>> dataSet = new ArrayList<>(chartDataSet.entrySet());
    List<Entry<String, Integer>> pointListOut = new ArrayList<>();
    reduce(dataSet, pointListOut);

    Map<String, Integer> reducedSeriesMap = new TreeMap<>();
    pointListOut.forEach(entry -> reducedSeriesMap.put(entry.getKey(), entry.getValue()));

    DecimalFormat numberFormat = new DecimalFormat("#.00");
    int pointListOutSize = pointListOut.size();
    String percentage =
        numberFormat.format((1 - ((double) pointListOutSize / (double) dataSet.size())) * 100);
    String reducedByMessage = pointListOutSize + " (" + percentage + "%)";
    AppViewModel.getInstance().setReducedByMessage((reducedByMessage));

    return reducedSeriesMap;
  }

  /**
   * Gets the perpendicular distance.
   * 
   * @param line The line object with the data
   * @return The perpendicular distance
   */
  private double getPerpendicularDistance(Line line) {
    double dx = line.getLineEndX() - line.getLineStartX();
    double dy = line.getLineEnd().getValue() - line.getLineStart().getValue();

    double mag = Math.hypot(dx, dy);
    if (mag > 0.0) {
        dx /= mag;
        dy /= mag;
    }
    double pvx = line.getPointX() - line.getLineStartX();
    double pvy = line.getPoint().getValue() - line.getLineStart().getValue();

    double pvdot = dx * pvx + dy * pvy;
    double ax = pvx - pvdot * dx;
    double ay = pvy - pvdot * dy;

    return Math.hypot(ax, ay);
  }

  /**
   * Reduces the number of points.
   */
  private void reduce(List<Entry<String, Integer>> pointList, List<Entry<String, Integer>> listOut) {
    int startIndex = 0;
    int endIndex = pointList.size() - 1;
    int index = 0;
    double maxDistance = 0;

    for (int i = startIndex + 1; i < endIndex; i++) {
      Line line = new Line.Builder()
          .setPoint(pointList.get(i))
          .setLineStart(pointList.get(startIndex))
          .setLineEnd(pointList.get(endIndex))
          .setPointX(i)
          .setLineStartX(startIndex)
          .setLineEndX(endIndex)
          .build();

      double distance = getPerpendicularDistance(line);

      if (distance > maxDistance) {
        index = i;
        maxDistance = distance;
      }
    }

    if (maxDistance > epsilon) {
      List<Entry<String, Integer>> result1 = new ArrayList<>();
      List<Entry<String, Integer>> result2 = new ArrayList<>();
      List<Entry<String, Integer>> firstLine = pointList.subList(startIndex, index + 1);
      List<Entry<String, Integer>> lastLine = pointList.subList(index, pointList.size());
      reduce(firstLine, result1);
      reduce(lastLine, result2);

      List<Entry<String, Integer>> result = new ArrayList<>(result1.size() + result2.size());
      result.addAll(result1);
      result.addAll(result2);

      listOut.addAll(result1.subList(startIndex, result1.size() - 1));
      listOut.addAll(result2);
    } else {
      listOut.clear();
      listOut.add(pointList.get(startIndex));
      listOut.add(pointList.get(pointList.size() - 1));
    }
  }

  /**
   * Sets the threshold epsilon.
   * 
   * @param epsilon The margin for the curve
   */
  public void setEpsilon(double epsilon) {
    this.epsilon = epsilon;
  }

}