samp17
samp17

Reputation: 577

JavaFX Realtime chart updates

This question has been asked before, multiple times, however I am still very confused as to how it specifically helps me.

I have a simple JavaFX XYChart. I want to perform FFTs on live data and display the updates in realtime. A lot more averaging will be done in the background, but essentially looking at 2-3Hz refresh rate on the chart.

I know there are other libraries and frameworks which make this easier, however they come with their own set of difficulties when working with javaFX, hence I would love to learn how to make this work for my needs.

So I have the following:

@FXML
public LineChart <Number, Number> midchart;

public void plotMidChart(){
    ArrayList freq = (ArrayList) Frequency.get(listViewIndex);
    ArrayList pha = (ArrayList) Phase.get(listViewIndex);

    for (int i=1; i<freq.size()-1; i++){
       phaseSeries.getData().add(new XYChart.Data<Number, Number>((Number) freq.get(i), (double) pha.get(i)));
    }

    phaseSeries.setName("Phase");   


    midchart.getData().addAll(phaseSeries );
}

This currently works as a 'one pass' method. And each time I call plotMidChart I can update the chart with whatever data I have selected (via listViewIndex). However this is currently quite slow to render and on the main thread.

Reading more, I have discovered that anything to do with changing the main JavaFX UI Thread should be called via 'Platform.runLater()) ->' So I tried to put the method into the following code:

Platform.runLater(() -> {
    ArrayList freq = (ArrayList) Frequency.get(listViewIndex);
    ArrayList pha = (ArrayList) Phase.get(listViewIndex);

    for (int i=1; i<(freq.size()-1); i++){
        System.out.println(i);
        phaseSeries.getData().add(new XYChart.Data<Number, Number>((Number) freq.get(i), (double) pha.get(i)));
        }
        midchart.getData().addAll(phaseSeries );
    });

Frequency and Phase are arrays of FFT results, so when I select a specific index, it returns the results for that FFT. However I am confused here, as surely all of the actual rendering is still being done on the main UI Thread. Isn't the point that it is done on another thread and just called to the scene on the UI thread?

I have read a bit about 'Task' but the oracle website still says this shouldn't be linked to the UI Thread.

I am also lost on how this is updating the current data. Each time this is called, I want it to overwrite the current data series, so that only one series is ever displayed, and each time it is a brand new set of data (not being added to existing data).

The end goal is to have this on an infinite loop, sleeping for approx 300ms between each iteration.

I am calling this plotMidChart() method via the following

measureList.setOnMouseClicked(new EventHandler<MouseEvent>(){

    @Override
    public void handle(MouseEvent event) {
        listViewIndex =  measureList.getSelectionModel().getSelectedIndex();
        plotMidChart();
        }
}

Upvotes: 0

Views: 1679

Answers (1)

Markus K&#246;bele
Markus K&#246;bele

Reputation: 293

So there are multiple issues you are bringing up here and I will try to address them all.

First of all Platform.runLater() will execute the code you give to it in the UI thread. So you perform heavy operations in your own thread and everything that affects the UI needs to be called within Platform.runLater().

What you could do is to create your data in your own thread and when this is done you give the result to the UI thread.

public void plotMidChart(){
    ArrayList freq = (ArrayList) Frequency.get(listViewIndex);
    ArrayList pha = (ArrayList) Phase.get(listViewIndex);

    List<XYChart.Data<Number, Number>> tempList = new ArrayList();
    for (int i=1; i<freq.size()-1; i++){
       tempList.add(.add(new XYChart.Data<Number, Number>((Number) freq.get(i), (double) pha.get(i)));
    }

    Platform.runLater(() -> {
       phaseSeries.getData().setAll(tempList);
    });
}

Also note that you don't need to call phaseSeries.setName("Phase") and midchart.getData().addAll(phaseSeries ) everytime you recreate the chart data.

If your performance still is really bad, it is possible that you are giving too many data points to the chart which can take quite some time to render.

Upvotes: 2

Related Questions