
When solving various analytical tasks, it may be necessary to have real-time graphing, where the function depends on time. In this article, I will share my experience in solving the problem of animating graphs in Qt using QCustomPlot.
Tools used
- Qt Creator 5.5.0
- QCustomPlot 1.3.1
QCustomPlot in brief
Drawing graphs occurs after calling the replot () method (manually, or when an event is triggered). To render this widget requires 2 data arrays containing the value of the argument (x) and the value of the function at this point (y).
Creating a schedule
For details, see the official. Tutorial on QCustomPlotFor clarity of the example, we will create a graph, the argument of which will be time in ms.
')
QVector<double> x(100), y(100); for(int i = 0; i < 100; i++) { x[i] = 100*i y[i] = x[i]; }
Create a graph, which we will later animate:
customplot->addGraph();
And give it a vector with input data:
customplot->graph(0)->setData(x,y);
Set the visible part of the graph equal to (0; 10,000) in x, and (0; 10,000) in y, so that the whole graph is visible:
customplot->xAxis->setRange(0, 10000); customplot->yAxis->setRange(0, 10000);
It remains to cause a replot:
customplot->replot();
This is how our schedule should look. Done! It remains only to directly make it consistently "draw."
Animation
For the animation, we will create a QTimer that will signal timeout () and call a function to draw the next value.
We also need a global variable that will store the elapsed time data from the start of the drawing, as well as 2 additional arrays for storing x, y, the purpose of which will be shown below.
int TimeElapsed = 0; QVector<double> x2, y2; ... QTimer* playBackTimer = new QTimer(this);
QTimer works in such a way that after calling the QTimer-> start method (int d) after d milliseconds, it signals timeout (), and then it is restarted until it is stopped by the QTimer-> stop () method. To get a fairly smooth image, set d = 50 (20 fps).
playBackTimer->start(50);
And now let's proceed directly to the implementation of the event handling function from the timer:
void PlaybackStep() { TimeElapsed+=50;
The animation mechanism is such that at each signal from the timer we take elements less than or equal in value to the variable storing the number of elapsed milliseconds.
Also, in order not to run through the entire array of input data each time, after adding them to the new x2, y2 arrays, we delete them with the help of pop_front ().
On each “frame” we update the graph data by calling setData (x2, y2), and also request a redraw of qcustomplot.
Ready animation example
This example is taken from the project under development.
I would like to add that, although it may seem that replot () is a rather expensive function to call it 20+ times per second, I measured the plot drawing speed. If there are 10 graphs, each with 20-30 values on the screen, the execution time of replot () did not exceed 1 ms, and the time taken to perform the entire PlaybackStep function <10 ms, which theoretically allows updating the graph with a frequency of ~ 100 fps.
PS This example is suitable for real-time rendering, where the graph function argument is time. However, the same mechanism can be adapted for drawing any other graphs where there is no time dependence.
UPD. Added an example of animated graphs (gif).