SciChart Android Tutorial - Adding Realtime Updates
In the previous tutorials we've showed how to Create a Simple Chart, add some Zoom and Pan interaction as well as Tooltips Inspection + Legends via the Chart Modifiers API.
In this SciChart Android tutorial we're going to go a little further and show how to update data displayed by a chart in real-time.
Getting Started
This tutorial is suitable for Java and Kotlin.
Note
Source code for this tutorial can be found at our Github Repository: Java and Kotlin Tutorials Repository
Assuming you have completed the previous tutorial, we will now make some changes to update the data dynamically.
Updating Data Values
In our IDataSeries<TX,TY>, we have some static data so far. Let's update them in real-time now.
We are going to add a Timer and schedule updating the data on timer tick.
To update data in a DataSeries, we will need to call one of the available Update
methods on that DataSeries.
Since we are using XyDataSeries<TX,TY>, we are going to use the updateXyAt(int index, TX x, TY y) method.
More information about Updating DataSeries can be found in the Manipulating DataSeries Data article.
But first of all, we need to adjust some previously created code and save DataSeries instances to be able update them later. And since we are going to change a DataSeries setup, it worth mentioning that the code from the previous tutorials works, but it wasn't very efficient:
- Calling any of the Update methods triggers a chart update, which redraws the entire chart.
- The values are passed in as Number objects, which require boxing/unboxing, which slows down the process as well
No worries, in SciChart there is an easy way to improve that:
- Make sure to always Append or Update data in a DataSeries in batches instead of one at a time.
- Suspend updates on a SciChartSurface using using(ISuspendable suspendable, Runnable runnable) to prevent redrawing until you have updated the whole DataSeries.
- Use one of the IValues<T> implementation such as DoubleValues. It stores data in an primitive array internally and doesn't requires boxing/unboxing.
So we updated the code as follows:
private int pointsCount = 200;
private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
private ScheduledFuture schedule;
private SciChartSurface surface;
private final DoubleValues lineData = new DoubleValues();
private XyDataSeries lineDataSeries;
private DoubleValues scatterData = new DoubleValues();
private XyDataSeries scatterDataSeries;
// ...
final IntegerValues xValues = new IntegerValues();
for (int i = 0; i < pointsCount; i++) {
xValues.add(i);
lineData.add(Math.sin(i * 0.1));
scatterData.add(Math.cos(i * 0.1));
count += 1;
}
lineDataSeries.append(xValues, lineData);
scatterDataSeries.append(xValues, scatterData);
From here, we can initialize our Timer and create an updateData
runnable, with real-time updates, like follows:
schedule = scheduledExecutorService.scheduleWithFixedDelay(updateData, 0, 10, TimeUnit.MILLISECONDS);
// ...
private Double phase = 0.0;
private final Runnable updateData = () -> {
for (int i = 0; i < pointsCount; i++) {
lineData.set(i, Math.sin(i* 0.1 + phase));
scatterData.set(i, Math.cos(i* 0.1 + phase));
}
UpdateSuspender.using(surface, () -> {
lineDataSeries.updateRangeYAt(0, lineData);
scatterDataSeries.updateRangeYAt(0, scatterData);
// zoom series to fit viewport size into X-Axis direction
surface.zoomExtentsX();
});
phase += 0.01;
};
Which will result in the following Chart:
Note
Despite the chart is now real-time, it's still fully interactive, you can use modifiers from previous tutorials with ease.
Adding New Data Values
As well as using updateXyAt(int index, TX x, TY y), you can also use append(TX x, TY y) (or any other available Append method) to add new data-values to a DataSeries.
The code from above can be updated as follows to append new data constantly to the dataSeries:
private Integer count = 0;
private final Runnable updateData = () -> {
Integer x = count;
UpdateSuspender.using(surface, () -> {
lineDataSeries.append(x, Math.sin(x* 0.1));
scatterDataSeries.append(x, Math.cos(x * 0.1));
// zoom series to fit viewport size into X-Axis direction
surface.zoomExtentsX();
count += 1;
});
};
Scrolling Realtime Charts
What if you wanted to scroll as new data was appended? You have a few choices.
- If you want to be memory efficient, and you don't mind if you discard old data, you can use our FIFO (first-in-first-out) functionality.
- If you want to preserve old data, you can simply update the visibleRange.
Since updating VisibleRange is fairly self-explanatory, we are going to explain the FIFO method.
Discarding Data when Scrolling using FifoCapacity
The most memory efficient way to achieve scrolling is to use fifoCapacity to set the maximum size of a DataSeries before old points are discarded. DataSeries in FIFO mode act as a circular - first-in-first-out - buffer. Once the capacity is exceeded, old points are discarded. You cannot zoom back to see the old points, once they are lost, they are lost.
To make a DataSeries use the FIFO buffer, all you need to do is just set fifo capacity on the DataSeries, e.g.:
lineDataSeries.setFifoCapacity(300);
scatterDataSeries.setFifoCapacity(300);
Note
After appending new data we call zoomExtents
to make series to fit the viewport.
The following should be the result when you run the application:
Where to Go From Here?
You can download the final project from our Java and Kotlin Tutorials Repository.
Also, you can found next tutorial from this series here - SciChart Android Tutorial - Annotations
Of course, this is not the limit of what you can achieve with the SciChart Android. Our documentation contains lots of useful information, some of the articles you might want to read are listed below:
Finally, start exploring. The SciChart Android library and functionality is quite extensive. You can look into our SciChart Android Examples Suite which are full of 2D and 3D examples, which are also available on our GitHub
In particular, you might want to take a look at our Fifo Scrolling Chart: