How to force QChartView to paint only part of itself

905 views Asked by At

I'm building an application that plots measurement data using the QtCharts library. Some important things that should be mentioned are:

  1. I am dealing with time series.

  2. The measurement data is obtained offline, which means it has already been obtained. My program just reads it from the file and displays it.

  3. I am working with a for-loop that takes the data points as chunks of a fixed size (say 10000) and adds them to the scatter series. This way, the data is being "replayed" and the user can see the progression of the measurement data at many intermediate time points and not just after all data points have been plotted.

  4. I am working with a whole lot of data points, on the order of millions.

At every iteration of the loop a new QScatterSeries is created, data points are appended, the scatter series is added to the chart and then the chart view is repainted. In the beginning it is quite fast, but as time progresses the number of points to be painted increases and the painting process becomes slower and slower. I know for a fact that I can reimplement the paintEvent of the chart view class to get it to redraw only part of itself. I think I can make it faster by updating only the parts that have new data points. I will just calculate the coordinates of the region where new data points were added and use the paintEvent. But how do I do it? I tried using the setClipRect() method of QPainter, but couldn't do it. Thanks in advance.

1

There are 1 answers

1
Kuba hasn't forgotten Monica On

QGraphicsView/QGraphicsItem don't implement it.

They don't because it's unfortunately generally impossible: the displayed items (e.g. series) are scaled and antialiased. In the old days when everything was displayed in device units, and was drawn directly on the window, doing partial updates made sense: you'd first use a fast blit to shift the existing plot, and then draw new points.

Alas, in any non-trivial scene viewer, the relationship between the horizontal device (widget) units and the item (chart/series) units is not 1:1, so there's no general way to scroll the data in device units and have it still make sense in chart units.

There are is a workaround: Scroll by some larger-than-needed (rounded up) number of device units, then back-calculate what scroll it yields in chart units, and then offset the chart by such a number (i.e. move the X axis range accordingly).

This could be implemented with relative ease in the sources of the QGraphicsView system, as the chart builds on it. There's no way to "bolt this on" externally - you need to add such support directly to QGraphicsView and QGraphicsItem infrastructure, and then have the QChartView leverage it. If you're not in the habit of building your own Qt, you can of course copy the necessary classes over to your codebase and rename them.