gpt4 book ai didi

java - 如何在 JAVAFX 2 中使用 AreaChart 绘制实时流数据图表 - 并发、动画、图表

转载 作者:太空狗 更新时间:2023-10-29 22:58:38 24 4
gpt4 key购买 nike

要求 - 使用实时流数据构建动画 AreaChart。也许每 1 秒绘制 300 个数据点。

详情-因此,我需要从医疗设备读取患者呼吸模式的实时流数据,并使用 JavaFX 中的 AreaChart 以波形方式显示它。我是 JavaFX 的新手,所以我构建了一个小型 POC,以了解并发性和动画在 JavaFX 中的工作原理。

这个概念可行,就实现功能而言,我对基本测试很满意。但是我对从下面的代码中获得的性能不满意。

在下面的工作代码中,我创建了一个单独的线程来模拟从医疗设备中获取数据。该线程只是生成一个随机数并将其添加到 ConcurrentLinkedQueue。

JavaFX 应用程序线程通过时间线从队列中拉出该数据,并将其添加到 AreaChart 系列。

这为我提供了所需的动画,并在运行时添加了数据。您可以复制粘贴此代码并对其进行测试。它应该可以工作。

但性能并不令人印象深刻 - CPU 使用率达到 56% - 我的笔记本电脑上有 Intel Core 2 Duo @ 2.53 GHZ 和 4GB 内存。我的显卡是带有最新驱动程序的 Mobile Intel 4 Series express。

如何改进实时数据的动画或绘图,以获得更好的性能?

注意:如果是瓶颈,我愿意在动画上妥协。我对此处所示的实现持开放态度 http://smoothiecharts.org/其中波形只是预构建的,只是从右到左流式传输。

  import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart.Series;
import javafx.stage.Stage;
import javafx.util.Duration;

/**
* A chart that fills in the area between a line of data points and the axes.
* Good for comparing accumulated totals over time.
*
* @see javafx.scene.chart.Chart
* @see javafx.scene.chart.Axis
* @see javafx.scene.chart.NumberAxis
* @related charts/line/LineChart
* @related charts/scatter/ScatterChart
*/
public class AreaChartSample extends Application {
private Series series;
private int xSeriesData=0;
private ConcurrentLinkedQueue<Number> dataQ = new ConcurrentLinkedQueue<Number>();
private ExecutorService executor;
private AddToQueue addToQueue;
private Timeline timeline2;
private SequentialTransition animation;

private void init(Stage primaryStage) {
Group root = new Group();
primaryStage.setScene(new Scene(root));

NumberAxis xAxis = new NumberAxis();
xAxis.setAutoRanging(true);

NumberAxis yAxis = new NumberAxis();
yAxis.setAutoRanging(true);

//-- Chart
final AreaChart<Number,Number> sc = new AreaChart<Number,Number>(xAxis,yAxis);
sc.setId("liveAreaChart");
sc.setTitle("Animated Area Chart");

//-- Chart Series
series=new AreaChart.Series<Number,Number>();
series.setName("Area Chart Series");
series.getData().add(new AreaChart.Data<Number, Number>(5d, 5d));
sc.getData().add(series);


root.getChildren().add(sc);



}

@Override public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();

//-- Prepare Executor Services
executor = Executors.newCachedThreadPool();
addToQueue=new AddToQueue();
executor.execute(addToQueue);


//-- Prepare Timeline
prepareTimeline();


}

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

private class AddToQueue extends Thread {

public void run(){

try {
Thread.currentThread().setName(Thread.currentThread().getId()+"-DataAdder");
//-- Add Random numbers to Q
dataQ.add(Math.random());
Thread.sleep(50);

executor.execute(addToQueue);

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

}
}

//-- Timeline gets called in the JavaFX Main thread
private void prepareTimeline(){
//-- Second slower timeline
timeline2 = new Timeline();
//-- This timeline is indefinite.
timeline2.setCycleCount(Animation.INDEFINITE);

timeline2.getKeyFrames().add(
new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent actionEvent) {
addDataToSeries();

}
})
);

//-- Set Animation- Timeline is created now.
animation = new SequentialTransition();
animation.getChildren().addAll(timeline2);
animation.play();

}

private void addDataToSeries(){

for(int i=0;i<20;i++){ //-- add 20 numbers to the plot
if(dataQ.isEmpty()==false) {
series.getData().add(new AreaChart.Data(xSeriesData++,dataQ.remove()));

//-- Get rid of a bunch from the chart
if (series.getData().size() > 1000) {
series.getData().remove(0,999);
}

}
else{
return;
}
}
}


}

最佳答案

作为jewelsea在他/她的评论中说:

This question was cross posted (and answered well) on an Oracle JavaFX forum thread.

总而言之,解决方案包括:

  • Turning animation off as it is designed for slower changing data so that it is animated on arrival;
  • Changing the Timeline to a AnimationTimer as it is desired to update the chart every frame in order to keep in sync with incoming data and move as smoothly as possible;
  • Fixing threading as OP did not need to extend Thread when using a Executor. Changing the creation of the executor service.

关于java - 如何在 JAVAFX 2 中使用 AreaChart 绘制实时流数据图表 - 并发、动画、图表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11306710/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com