在PyQtGraph中绘制大时间序列时使用预先下采样的数据(Using pre

编程入门 行业动态 更新时间:2024-10-24 16:33:05
在PyQtGraph中绘制大时间序列时使用预先下采样的数据(Using pre-downsampled data when plotting large time series in PyQtGraph)

我需要在PyQtGraph中绘制一个大的时间序列(数百万点)。 按原样绘制它几乎是不可能的,当打开优化选项(使用setDownsampling下采样并使用setClipToView进行裁剪)时,它在缩小时仍然几乎无法使用(只有在放大时才会因为裁剪而变快)。

我有个主意。 我可以预先对我的数据进行下采样,因为它们是静态的。 然后,我可以在缩小时使用缓存的下采样数据,并在放大时使用原始数据。

我怎样才能做到这一点?

I need to plot a large time series in PyQtGraph (millions of points). Plotting it as is is practically impossible and when turning on the optimization options (downsampling using setDownsampling and clipping using setClipToView) it is still barely usable when zoomed out (only when zoomed in it becomes fast thanks to clipping).

I have an idea though. I could pre-downsample my data since they're static. Then, I could use the cached downsampled data when zoomed out and the raw data when zoomed in.

How can I achieve that?

最满意答案

我在一个名为runviewer的项目中做过类似的事情。 一般的想法是每当绘图的x范围改变时重新采样数据。 我们使用的近似方法是:

将方法连接到sigXRangeChanged信号,该信号设置一个布尔标志,指示需要重新采样的数据。

启动一个线程,每隔x秒(我们选择0.5秒)轮询布尔标志,看看是否需要对数据进行重采样。 如果是,则使用您选择的算法重新采样数据(我们在C中编写了自己的算法)。 然后将这些数据发回主线程(例如,使用QThread并向主线程发回信号),其中调用pyqtgraph来更新绘图中的数据(注意,您只能从中调用pyqtgraph方法)主线!)

我们使用布尔标志将x范围更改事件与重采样分离。 您不希望每次x范围更改时重新采样,因为当您使用鼠标进行缩放时,信号会多次触发,并且您不希望生成重新采样调用的队列,因为重新采样很慢,即使使用C !

您还需要确保重新采样线程在检测到为True时立即将布尔标志设置为False,然后运行重采样算法。 这使得在当前重采样期间的后续x范围改变事件导致随后的重采样。

您也可以通过不轮询标志,但使用某种线程事件/条件来改善这一点。

请注意,使用Python进行重新采样非常非常慢,这就是我们选择编写重采样算法C并从Python调用它的原因。 numpy主要在C中,所以会很快。 但是我不认为他们有一个保留重采样算法的功能。 大多数重新采样的人只是标准的下采样,你可以在每个N点采用,但我们仍然希望在缩小时能够看到小于采样大小的特征。


关于绩效的补充评论

我怀疑pyqtgraph内置方法的部分性能问题是下采样是在主线程中完成的。 因此,必须在图形再次响应用户输入之前完成下采样。 我们的方法避免了这一点。 我们的方法还限制了下采样发生的次数,最多是每次下采样the length of time it takes to down-sample + the poll delay秒数。 因此,随着我们使用的延迟,我们每隔0.5-1秒仅下采样,同时保持主线程(以及UI)响应。 它确实意味着如果用户快速放大,用户可能会看到粗略采样的数据,但这在最多2次重采样迭代中得到纠正(因此最多延迟1-2秒)。 此外,由于纠正需要很短的时间,因此使用新采样数据进行更新/重绘通常在用户完成与UI的交互之后进行,因此他们在重绘期间不会注意到任何无响应。

显然,我引用的时间完全取决于重采样的速度和轮询延迟!

The answer by @three_pineapples describes a really nice improvement over the default downsampling in PyQtGraph, but it still requires performing the downsampling on the fly, which in my case is problematic.

Therefore, I decided to implement a different strategy, namely, pre-downsample the data and then select either the already downsampled data or the original data depending on the "zoom level".

I combine that approach with the default auto-downsample strategy employed natively by PyQtGraph to yield further speed improvements (which could be further improved with @three_pineapples suggestions).

This way, PyQtGraph always starts with data of much lower dimensionality, which makes zooming and panning instantaneous even with a really large amount of samples.

My approach is summarized in this code, which monkey patches the getData method of PlotDataItem.

# Downsample data downsampled_data = downsample(data, 100) # Replacement for the default getData function def getData(obj): # Calculate the visible range range = obj.viewRect() if range is not None: dx = float(data[-1, 0] - data[0, 0]) / (data.size[0] - 1) x0 = (range.left() - data[0, 0]) / dx x1 = (range.right() - data[0, 0]) / dx # Decide whether to use downsampled or original data if (x1 - x0) > 20000: obj.xData = downsampled_data[:, 0] obj.yData = downsampled_data[:, 1] else: obj.xData = data[:, 0] obj.yData = data[:, 1] # Run the original getData of PlotDataItem return PlotDataItem.getData(obj) # Replace the original getData with our getData plot_data_item.getData = types.MethodType(getData, plot_data_item)

更多推荐

本文发布于:2023-08-07 20:41:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1465613.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:序列   时间   数据   PyQtGraph   pre

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!