PDA

View Full Version : Fast curve plotting



Cruz
31st December 2011, 05:56
Hello!

I want to plot a lot of data on the screen. I draw curves made from a lot of little lines connecting the neighbouring data points and this typically leads to a laggy widget. I'm not using Qwt because I have some custom requirements such as being able to drag and scale the curves with the mouse and I figured it would be easier to implement those using just native Qt.

Anyhow, I could just plot all the curves once on a QPixmap and then show the pixmap in the paintEvent() and draw some additional things on top that are fast to draw. The only problem with this is zooming. If I zoom in by using painter.scale(), the lines on the pixmap get thick and edgy. I can't repaint the whole pixmap with every zoom operation.

Does anyone have an idea how I can solve the zooming problem? What technique does Qwt use to draw the plots?

Thanks,
Cruz

wysota
1st January 2012, 21:35
Basically you have two choices. Either you implement your plot in Graphics View and then you get zooming practically for free or you implement your plot using a custom engine and in such case you'll have to recalculate and redraw the visible subarea of the plot yourself whenever the user changes the zoom level or pans the view (in case this applies to your situation). As far as I know Qwt uses the latter technique.

Cruz
2nd January 2012, 00:26
Thanks Wysota. But I think I need to rephrase my question.

Calculating the visible area and drawing only the necessary portions of the curves is what I have now and it's still too slow, because there is just so much data on the screen. So the question is, what's the fastest way to plot a lot of data on the screen and still provide zooming and paning functionalities?

I believe that the graphics view framework will not help here. It may be fast in identifying the items in a small portion of a graphics scene and then rendering only what's necessary, but it will be just as slow when you have many visible items, because "by default, the items are drawn onto the viewport by using a regular QPainter, and using default render hints.". So graphics view would do just the same as I do now and assumably Qwt does too.

A second alternative could be to use OpenGL. This would also be possible in combination with the graphics view framework. But it would still have to render all the lines with every paint event, so I don't know how much faster it would be.

A third alternative may be to use SVG. SVG rendering supports zooming and paning, but due to the nature of vector graphics it would still have to explicitly render all the lines when they are shown on the screen, so again I'm not sure if it's any faster than just simple QPainter commands.

Using pixmaps is the only way I see to achieve a real speed up in at least some cases. Assuming I have all the lines rendered on a pixmap already, then a paning operation could be implemented extremely fast by just translating the pixmap a bit and rendering only the small portion of the screen that wasn't visible before. But for zooming operations a pixmap is still completely useless.

wysota
2nd January 2012, 02:00
Calculating the visible area and drawing only the necessary portions of the curves is what I have now and it's still too slow, because there is just so much data on the screen. So the question is, what's the fastest way to plot a lot of data on the screen and still provide zooming and paning functionalities?
There is no simple answer to that question. Basically you need to cache as much as possible and avoid calculating anything while drawing.


A second alternative could be to use OpenGL.
Not really. Drawing is unlikely to be a bottleneck here.


Using pixmaps is the only way I see to achieve a real speed up in at least some cases. Assuming I have all the lines rendered on a pixmap already, then a paning operation could be implemented extremely fast by just translating the pixmap a bit and rendering only the small portion of the screen that wasn't visible before. But for zooming operations a pixmap is still completely useless.

Using pixmaps is fine but it is not a solution to zooming. Whenever you change the zoom level, you have to discard the pixmap, recalculate everything, rerender the pixmap and then blit it to the widget. There is no free beer here, it's only a matter of how much you calculate and when (and how, i.e. using QImage and a thread might help but is not an ultimate solution per se).

Uwe
3rd January 2012, 11:35
So graphics view would do just the same as I do now and assumably Qwt does too.

About Qwt:


Qwt ( in opposite to pure QPainter or QGraphicsView ! ) clips before it renders. Compared to rendering the clipping algorithm ( Sutherland Hodgeman ) is pretty fast - that's why Qwt is much faster for zoomed scenes with many points.
Qwt also offers an implementation of the Douglas Peucker algo, that lets you reduce the number of points heavily according to the resolution of your paint device
Qwt offers a panner, that grabs the current scene to a pixmap moving the pixmap while panning. This has some drawbacks ( empty areas for new region ), but the performance doesn't depend on the scene.

Qwt also has other optimizations for specific situations, believe me - there is more substance behind curve plotting, than one expects in the beginning.

Uwe