Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback, please email oracle-forums_moderators_us@oracle.com

How to Chart real time streaming data using AreaChart in JAVAFX 2

947710Jul 5 2012 — edited Jul 9 2012
Requirement- Build an animated AreaChart with real time streaming data. Maybe plot 300 data points every 1 sec.

Details- So I need to read real time streaming data from a medical device, of a patient's breathing pattern and display it in a waveform fashion using AreaChart in JavaFX. I'm new to JavaFX and so I built a small POC, to see how concurrency and animation works in JavaFX.

The concept works and I'm happy with the basic test, as far as implementing the functionality. But I'm not happy with the performance I'm getting from the code below.

In the working code below, I create a separate thread to simulate data fetching from the medical device. The thread just generates a random number and adds it to a ConcurrentLinkedQueue.

The JavaFX Application thread pulls this data out from queue, via the Timeline, and adds it to an AreaChart Series.

This sort of gives me the animation I need and the data is being added in run time. You can copy-paste this code and test it..It should work.

BUT the performance is not impressive - CPU goes to 56% usage - I have a Intel Core 2 Duo @ 2.53 GHZ and 4GB ram on my laptop. My graphics card is Mobile Intel 4 Series express with latest driver.

How can I improve this animation or plotting of real time data, in order to get better performance?

NOTE: I'm willing to compromise on the animation, if its the bottle neck. I'm open to an implementation like shown here
http://smoothiecharts.org/ where the waveform is just prebuilt and just streaming from right to left.





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;
+}+
+}+
+}+


+}+

Edited by: 944707 on Jul 5, 2012 11:11 PM

Edited by: 944707 on Jul 6, 2012 9:15 AM
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Aug 6 2012
Added on Jul 5 2012
5 comments
21,611 views