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

2023-12-25

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

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

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

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

JavaFX 应用程序线程通过时间线从队列中提取这些数据,并将其添加到区域图系列中。

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

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

我怎样才能改进这个动画或实时数据的绘制,以获得更好的性能?

注意:如果动画是瓶颈的话,我愿意在动画上做出妥协。我对这里所示的实现持开放态度http://smoothiecharts.org/ 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;
              }
          }
      }


  }

As jewelsea https://stackoverflow.com/users/1155209/jewelsea在他/她的评论中指出:

这个问题被交叉发布(并得到了很好的回答)Oracle JavaFX 论坛主题 https://forums.oracle.com/forums/thread.jspa?threadID=2411087.

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

  • 关闭动画,因为它是为较慢变化的数据而设计的,以便在到达时呈现动画;
  • 改变Timeline to a AnimationTimer因为需要每帧更新图表,以便与传入数据保持同步并尽可能顺利地移动;
  • 修复线程,因为 OP 在使用 Executor 时不需要扩展 Thread。更改执行器服务的创建。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • 在Java Servlet中获取通过jquery ajax发送的参数[重复]

    这个问题在这里已经有答案了 我在网上搜索这个主题 但找不到有效的示例 我会很高兴有人能给我帮助 这就是我测试的 ajax url GetJson type POST dataType json contentType application
  • 来自行号的方法名称

    给定特定类源代码 Java C 的行号 是否有一种简单的方法来获取它所属的方法的名称 如果它落入其中 大概使用抽象语法树 这对于将 checkstyle 的输出限制为仅触及的方法很有用 我假设您必须使用抽象语法树来执行 Line gt Me
  • IBM Websphere MQ - 用于 Tomcat 部署的 EJB 和 MDB 迁移

    我已经为此苦苦挣扎了很长一段时间 我有一个 IBM Websphere MQ 它使用 EJB 和 MDB 以下是配置ejb mdb的地方
  • 从 Android 函数更新 Textview

    有人可以告诉我如何从函数更新 Android Textview 控件吗 我在互联网上进行了深入搜索 看到很多人都问同样的问题 我测试了线程但无法工作 有人有一个简单的工作示例吗 例如 调用一个函数 在循环中运行多次 并且该函数在 TextV
  • Java:为什么.class文件中的方法类型包含返回类型,而不仅仅是签名?

    class 文件的常量池中有一个 NameAndType 结构 它用于动态绑定 该类可以 导出 的所有方法都被描述为 签名 返回类型 喜欢 getVector Ljava util Vector 当某些 jar 中方法的返回类型发生更改时
  • Java 错误和警告列表

    在哪里 如何获得所有 java 和 javac 的错误和警告消息的列表 This http mindprod com jgloss compileerrormessages html我认为页面是您所需要的
  • 使用 Spring MVC 在 jar 文件中显示 jsp 页面

    我正在使用 Spring MVC 3 2 2 在 java 中开发一个 Web 应用程序 我在从 jar 文件中加载 jsp 页面时遇到问题 Spring MVC Web应用程序具有以下结构 META INF WEB INF spring
  • Spring 从 JBoss 上下文加载 PropertySourcesPlaceholderConfigurer

    我有一个使用 PropertySourcesPlaceholderConfigurer 的 spring 3 1 应用程序加载设置 我想管理测试和生产环境 只需从服务器上下文加载设置覆盖本地文件属性中指定的设置 下一个示例在 Tomcat
  • ggplot 中跨组的连续线

    我有一个数据时间序列 其中观察了一些数据 模拟了一些数据 我想生成整个数据系列随时间变化的图 其中颜色表示数据源 但是 我只能弄清楚如何使 ggplot 中的 geom line 连接同一组中的点 这是一个例子来说明 Create samp
  • 如何检查单词是否在wordNet中

    我开始了解wordNet直到我知道我找到了synonymous对于一个特定的词 现在我有一个文件 我想使用标记化该文本n gram例如 String s I like to wear tee shirt 使用后n gram这将是 I lik
  • 从字符串中删除重音符号

    Android 中有没有什么方法 据我所知 没有 java text Normalizer 可以从字符串中删除任何重音 例如 变成 eau 如果可能的话 我想避免解析字符串来检查每个字符 java text NormalizerAndroi
  • 如何获取 JDBC 中 UPDATE 查询影响的所有行?

    我有一项任务需要使用更新记录PreparedStatement 一旦记录被更新 我们知道更新查询返回计数 即受影响的行数 但是 我想要的不是计数 而是受更新查询影响的行作为响应 或者至少是受影响的行的 id 值列表 这是我的更新查询 UPD
  • React Native v0.71.8 React-native-vector-icons 你看不到的图标

    我在用react native版本v0 71 8 我安装了react native vector icons库 但图标未显示 似乎链接在最新版本的 React Native 中不再起作用 所以我按照说明进行操作 但它不再编译 出现以下错误
  • Spring Security 角色层次结构不适用于 Thymeleaf sec:authorize

    我正在使用 Spring Security 3 2 5 RELEASE 和 ThymeLeaf 2 1 4 RELEASE 我已经在安全上下文中定义了角色层次结构 在我的视图层中我正在使用sec authorize属性来定义菜单项 我希望看
  • 在 Eclipse RCP 应用程序中禁用插件贡献

    我经常遇到这个问题 但尚未找到解决方案 每当我编写一个新的基于 Eclipse RCP 的应用程序并包含来自 Eclipse 平台的插件时 我都会 继承 其中一些插件的 UI 贡献 大多数贡献 菜单项 键盘快捷键 属性页 都很有用 但有时我
  • 线程数组?

    所以我在理解如何避免线程的顺序执行时遇到了问题 我试图创建一个线程数组并在单独的循环中执行 start 和 join 函数 这是我现在拥有的代码示例 private static int w static class wThreads im
  • 难以理解 通配符

    我有一个非常基本的问题 下面的代码无法编译 假设 Apple Extends Fruit List
  • 用于生成 ISO 文件的 Maven 插件

    有没有可以生成ISO镜像的maven插件 我需要获取一些模块的输出 主要是包含 jar 的 zip 文件 并将它们组合成一个 ISO 映像 Thanks 现在有一个 ISO9660 maven 插件可以完成这项工作 https github
  • 假布尔值=真?

    我在一本书中找到了这段代码 并在 Netbeans 中执行了它 boolean b false if b true System out println true else System out println false 我只是不明白为什
  • MyBatis 枚举的使用

    我知道以前有人问过这个问题 但我无法根据迄今为止找到的信息实施解决方案 所以也许有人可以向我解释一下 我有一个表 状态 它有两列 id 和 name id是PK 我不想使用 POJO Status 而是使用枚举 我创建了这样一个枚举 如下所

随机推荐