JavaFX LineChart Performance

What is improving the performance of charts with many data points, is to remove the 'shape' of the data points.

Over css for example:

.chart-line-symbol {
    -fx-shape: "";
}

or to make sure it's not visible at all:

.chart-line-symbol {
   -fx-background-insets: 0,0;
   -fx-background-radius: 0px; 
   -fx-padding: 0px;
   -fx-shape: "";
   -fx-background-color: transparent;
}

Another approach is to remove some data points from your chart. So for example only use every 3. datapoint or calculate the average of multiple data points.


Hope this comment is not in vain or comes too late:

Some of the performance limitations are intrinsic to the JavaFX implementation: ie. many operations being computed within the JVM rather than being pushed to the underlying OpenGL-based HW, data points being excessively large Nodes drawn within a scene graph rather than on-the-fly data reduction and usage of Canvas... to name a few. Unfortunately, we found that many of these issues (and bugs) could not be solved without larger workarounds (e.g.final API methods) around the original JavaFX Chart API.

We thus developed/re-designed (for our in-house application), open-sourced, and -- in the hope that others find it useful or want to contribute -- published our JavaFX-based charting library at GitHub:

https://github.com/GSI-CS-CO/chart-fx

Its primary focus: performance optimised real-time data visualisation at 25 Hz update rates for data sets with a few 10 thousand up to 5 million data points common in digital signal processing applications. Performance plots, examples and documentation are available at GitHub:

https://github.com/GSI-CS-CO/chart-fx/raw/master/docs/pics/chartfx-example1.png https://github.com/GSI-CS-CO/chart-fx/raw/master/docs/pics/chartfx-performance1a.png https://github.com/GSI-CS-CO/chart-fx/raw/master/docs/pics/chartfx-performance1.png

The motivations why a new JavaFX library was necessary and performance comparisons w.r.t. other Java and C++/Qt based libraries have been presented at IPAC'19: https://ipac2019.vrws.de/papers/thprb028.pdf

N.B. this is my first post, thus no in-line images


3 years later and is not a final solution as there are performance issues with big data but this help a lot (of course with this the chart will be simpler):

CSS (you can also play with other elements in the css to speed it up, a little)

.chart-vertical-grid-lines, .chart-horizontal-grid-lines {
    -fx-stroke: transparent;
}

Controller (this part is the one that consumes more time)

lineChart.setCreateSymbols(false); //this part is the one that consumes more time
lineChart.setAnimated(false);

Note: this issue is the same for any chart with lots of data.


I am also using JavaFX charts for a scientific application with tens of thounsands of data points, and have been able to achieve real-time speeds for updating and drawing a graph. There are two main things you need to do.

Firstly, the Ramer-Douglas-Peucker algorithm is unnecessarily complex, I think. Assuming you're working with a nice simple continuous function it's much easier to observe that we only have a limited display resolution and we don't need more than at most three or four data points for every pixel in the domain to convey as much information as possible. For example, one each for the first and last data point to occur within a pixel, and one each for the maximum and minimum within the pixel.

There are a few variations you can try on this strategy but the basic idea is just a nice quick single-pass downsample, and it should basically be lossless. (Or more accurately, it should add no extra representational loss on top of that of rasterisation.) It also limits the number of points to something manageable, and in my experience is fast enough to redraw on zoom or for real-time data updates. It may however cause problems if you have display scaling for HiDPI or are otherwise scaling your graph components for any reason.

The second part is just as important: even if you set the css to not draw the data point shapes, it still takes an inexplicably long time to add the nodes to the scene. To address this it seems sufficient to subclass LineChart and override the dataItemAdded method to be a no-op in the case that you don't want shapes drawn. You should also re-use the data points which are already added to the series where possible rather than add new ones, i.e. prefer series.getData().get(i).setXValue(...) and series.getData().get(i).setYValue(...) to series.setData(...) or series.getData().add(...).