PDA

View Full Version : Stride on QwtPlotCurve/QwtSeriesData



ifhmcos
20th February 2018, 18:25
I have a graph that needs to be updated in real time, for this I have a class that inhertis from QwtSeriesData<QPointF> and implements the methods sample and size, this series is attached to a QwtPlotCurve. Now the thing is that when adding a ton of points (not that many around 10K) the replotting gets super slow. I have pinpointed this to qwt trying to plot ALL the points in my series data irrespectively of my axis range. So I added a stride check on the sample method



QPointF linear_data::sample(size_t i) const {
if (i * stride < data.size()) {
QPointF res(i, data[i * stride]);
return res;
}
}

where stride is the maximum number of points im allowing in my QwtSeries (around 25K) divided by the widget size in pixels (this size is the same as the xBottom scale).

Is there a way to avoid doing this from my class that inherits from QwtSeriesData and force the QwtPlot to apply this stride instead? seems my 'fix' is not very general.

In short: My axis range is 0 to N, my point range is 0 to M, is there a way to tie these ranges so it doesn't graph all M points and instead graph N points?

Uwe
20th February 2018, 20:52
I have pinpointed this to qwt trying to plot ALL the points in my series data irrespectively of my axis range.
There are several way to reduce the number of points to be painted and the default setting is QwtPlotCurve::ClipPolygons | QwtPlotCurve::FilterPoints.
So your at least points outside the visible ranges are not painted.

In case of having many points with monotonic in/decreasing x or y coordinates I recommend to check the new QwtPlotCurve::FilterPointsAggressive that is available in SVN trunk.
It limits the number of points to a maximum of 4 points per pixel.

While the algos above are pretty fast and can be done for each render cycle you could also consider to use QwtWeedingCurveFitter. But this one is expensive and has to be done in advance.
Of course you could also implement your own type of QwtSeriesData, that returns every nth point, but I would consider the other ways of filtering being the better approach.

But 10K is not a number of points, that is expected making a plot being that slow. Guess you have antialiasing enabled, but there is probably even more, what goes wrong and is worth to be understood.
If you have a small compiler demo I can have a look at it.

Uwe

ifhmcos
21st February 2018, 16:20
There are several way to reduce the number of points to be painted and the default setting is QwtPlotCurve::ClipPolygons | QwtPlotCurve::FilterPoints.
So your at least points outside the visible ranges are not painted.

In case of having many points with monotonic in/decreasing x or y coordinates I recommend to check the new QwtPlotCurve::FilterPointsAggressive that is available in SVN trunk.
It limits the number of points to a maximum of 4 points per pixel.

While the algos above are pretty fast and can be done for each render cycle you could also consider to use QwtWeedingCurveFitter. But this one is expensive and has to be done in advance.
Of course you could also implement your own type of QwtSeriesData, that returns every nth point, but I would consider the other ways of filtering being the better approach.

But 10K is not a number of points, that is expected making a plot being that slow. Guess you have antialiasing enabled, but there is probably even more, what goes wrong and is worth to be understood.
If you have a small compiler demo I can have a look at it.

Uwe

Thanks for your response, I forgot to say that this is for a mobile application :). Right now I have a lot of jitter that I might try to fix averaging between the points in each stride.

This is what I have done so far: https://gist.github.com/araml/1435231c47da868d37abd9470480d5f0

Edit: It would also be cool if I didn't have to depend on this stride and qwt take care of it, meaning if I set the axisScale to be from 0 to 25K (my max) and then pass it a series with that size for qwt to "resize" accordingly. Right now I'm depending on the graph width being the same as the scale, and refixing my graph from the values in my class inheriting from QwtSeriesData, but I don't know if this is possible.

Uwe
22nd February 2018, 06:06
Edit: It would also be cool if I didn't have to depend on this stride and qwt take care of it, meaning if I set the axisScale to be from 0 to 25K (my max) and then pass it a series with that size for qwt to "resize" accordingly.
The QwtPlotCurve::FilterPointsAggressive mode is a better solution to the problem and works like you have suggested. Simply use Qwt from SVN trunk and enable this flag instead of your stride.

Uwe

ifhmcos
23rd February 2018, 13:11
The QwtPlotCurve::FilterPointsAggressive mode is a better solution to the problem and works like you have suggested. Simply use Qwt from SVN trunk and enable this flag instead of your stride.

Uwe

Thanks again for your answer and help. Although I tried (still trying) to use the svn trunk version, there seems to be a problem with Qt deploying the shared library to android (I'm still trying to fix it).

ifhmcos
23rd February 2018, 18:55
Thanks again for your answer and help. Although I tried (still trying) to use the svn trunk version, there seems to be a problem with Qt deploying the shared library to android (I'm still trying to fix it).

I'm back with a few more dumb questions. I'm trying to shift the whole graph but I get a lot of jitter, is there a way to draw just the last piece of the image while shifting the image an amount of pixels instead of redrawing from qwt? Like accessing the back buffer shifting it 10px, drawing the last 10px for example and presenting that? Right now I'm shifting the graph by doing this



void plotter::update_graphic() {
linear_data *ld = static_cast<linear_data *>(curves[0]->data());

int added_points = ld->added_points;

if (added_points && ld->full()) {
for (size_t i = 0; i < curves.size(); i++) {
ld = static_cast<linear_data *>(curves[i]->data());
ld->add_stride(added_points);
ld->added_points = 0;
}

grid_offset = grid_offset + added_points;
setAxisScale(xBottom, grid_offset, + grid_offset + 2000, step);
}

QwtPlot::replot();
points_frame = 0;
}

https://gist.github.com/araml/cb2fc413cfa57b065a193c4f33f80ff4

Which basically adds an offset to both the grid and the points, and reset the axis scale with that offset.

Thanks!