Solved Updating a QtChart "manually"
-
Hi,
I have been struggling with QtCharts for a bit now, the problem I am facing is the following:
I have got a QtChart which shows a live chart of measured data, the embedded device receives new data each 5ms(200hz). Look at it as a heart monitor: old heartbeats will be removed when a new heartbeat is appended.
Preferably the chart would update 200 times a second since the data I receive is at 200hz, while it is doable to update this fast on a desktop(it does work on my desktop), my embedded device is simply not fast enough. I have already tried to append only 1 out of 10 values the device receives. While this does work, the graph which is drawn is not a correct representation of the data.What I am looking for is appending and removing data without updating the chart itself. After let's say 10 appends/removes the chart get's updated "manually" , this will thus show all data but will only be updated 1 out 10 appends. By updating it manually I am hoping to reduce the load to be able to show all points on the chart.
What I have tried to do to achieve the manual updating is the following:
I've blocked the signals from the QSplineSeries to prevent the chart from updating. This does work but the part I am actually stuck at is that I am not able to update the QChart "manually". I have tried looking in the source code of QSplineSeries to see what kind of Signal it emits but it looks more like a maze to me than readable code.Does anyone know a solution to be able to update the qchart manually? Or does anyone know a solution to be able to reduce load and be able to update the chart as close as possible to 200 times a second.
Best regards,
Martijn
-
Okay I might have an idea which might work:
Instead of 2 QSplineseries(serieA and serieB) I am going to create 4(serieA, serieA2, serieB, serieB2). Only 2 QSplineSeries will be shown at the same time either serieA and serieB or serieA2 and serieB2. While showing serieA and serieB are added to the Chart all new values will be appended to the serieA2 and serieB2. When X amount of new values are added to serieA2 and serieB2 I will remove serieA and serieB and add serieA2 and serieB2. When serieA2 and serieB2 are added all values will be appended to serieA and serieB and so on. Because the new values are appended on a series which is not currently in the chart the chart won't update and will only update when I add the seriesA and serieB as a whole.
When I finished implementing this I will add the outcome in this post underneath.
Update with solution:
@Gojir4 Thanks for brainstoriming with me, sometimes all you need is someone to talk to. Your suggestion for an extra buffer helped alot!I've found a solution for my problem and it almost as I described above.
void Chart::appendValue(unsigned long long xValue, uint16_t yValue) { count++; double place = double((xValue % (SECONDS_SHOWN_ON_SCREEN * 1000)) / double(SECONDS_SHOWN_ON_SCREEN * 1000)) * SECONDS_SHOWN_ON_SCREEN; if (count == MEASUREMENTS_PER_CHART_UPDATE) { count = 0; removeSeries(m_series); removeSeries(n_series); m_series = m2_series; n_series = n2_series; addSeries(m_series); addSeries(n_series); m_series->attachAxis(m_ax); n_series->attachAxis(m_ax); m_series->attachAxis(m_ay); n_series->attachAxis(m_ay); } if (previousX > place) { m_seriesActive = !m_seriesActive; } if (m_seriesActive) { m2_series->append(place, yValue); } else { n2_series->append(place, yValue); } this->previousX = place; handleTimeout(); }
I still have the "double series" as a buffer, all new values are appended to the buffer series which is not shown on the chart. When the counter hits the desired amount of new points per update the old series are removed from the chart. The buffer series are copied to the series which are shown on the chart and the shown series are added to the chart again. It is significantly faster on my desktop but I have not tested it on my embedded device yet.
If anyone has a better/easier solution feel free to post it!
-
@NachoFly said in Updating a QtChart "manually":
I've blocked the signals from the QSplineSeries to prevent the chart from updating.
Hi,
Can't you "unblock" the signal from time to time to update the chart ?
-
@Gojir4
Hi, Thanks for the response, I forgot to mention that I already tried that. Unfortunately this does not work and causes a segmentation fault. The segmentation fault is most likely caused by the fact that removing and adding a point on a QSplineseries cause two different signals and not just a general signal which tells the chart that the QSplineseries has changed.
During the time the QSplineseries' signals were blocked the chart missed signals from the removed and added points. When the QSplineseries' their signals get unblocked and send a new "pointAdded" or "poinRemoved" signal the chart will most likely only process the point which was just added/removed and caused the signal.
The fact that it most likely only processes the point which caused the signal probably causes the segmentation fault since the new point should be "connected" with a line to the point before that point. Since this point was never added to the chart my best guess is that this causes a segmentation fault. -
@NachoFly Ok, I see, thanks for the explanation.
So you could use a QVector or QList to store your points, acting like a buffer, and then updating the chart at the frequency you want. So instead of adding 1 out of 10 value, you will add 10 (or 5, or 20...) values at once. Which I think will be probably better in performance, without losing data.
-
@Gojir4
I also considered doing that and it indeed sounds like the solution to go with. Unfortunately using the append(const QList<QPointF> &) will just call append(const QPointF &) as many times as there are points in the QList and will thus cause as many signals and updates as adding each point seperately. -
Okay I might have an idea which might work:
Instead of 2 QSplineseries(serieA and serieB) I am going to create 4(serieA, serieA2, serieB, serieB2). Only 2 QSplineSeries will be shown at the same time either serieA and serieB or serieA2 and serieB2. While showing serieA and serieB are added to the Chart all new values will be appended to the serieA2 and serieB2. When X amount of new values are added to serieA2 and serieB2 I will remove serieA and serieB and add serieA2 and serieB2. When serieA2 and serieB2 are added all values will be appended to serieA and serieB and so on. Because the new values are appended on a series which is not currently in the chart the chart won't update and will only update when I add the seriesA and serieB as a whole.
When I finished implementing this I will add the outcome in this post underneath.
Update with solution:
@Gojir4 Thanks for brainstoriming with me, sometimes all you need is someone to talk to. Your suggestion for an extra buffer helped alot!I've found a solution for my problem and it almost as I described above.
void Chart::appendValue(unsigned long long xValue, uint16_t yValue) { count++; double place = double((xValue % (SECONDS_SHOWN_ON_SCREEN * 1000)) / double(SECONDS_SHOWN_ON_SCREEN * 1000)) * SECONDS_SHOWN_ON_SCREEN; if (count == MEASUREMENTS_PER_CHART_UPDATE) { count = 0; removeSeries(m_series); removeSeries(n_series); m_series = m2_series; n_series = n2_series; addSeries(m_series); addSeries(n_series); m_series->attachAxis(m_ax); n_series->attachAxis(m_ax); m_series->attachAxis(m_ay); n_series->attachAxis(m_ay); } if (previousX > place) { m_seriesActive = !m_seriesActive; } if (m_seriesActive) { m2_series->append(place, yValue); } else { n2_series->append(place, yValue); } this->previousX = place; handleTimeout(); }
I still have the "double series" as a buffer, all new values are appended to the buffer series which is not shown on the chart. When the counter hits the desired amount of new points per update the old series are removed from the chart. The buffer series are copied to the series which are shown on the chart and the shown series are added to the chart again. It is significantly faster on my desktop but I have not tested it on my embedded device yet.
If anyone has a better/easier solution feel free to post it!
-
@NachoFly It looks like a good approach. I didn't know that about append(), thanks for notice.
The only thing I would try is replacing the data instead of having two series, using void QXYSeries::replace(QVector<QPointF> points). It could be interesting to see which solution is faster.