Python - 使用 pyqtgraph (16ms) 快速绘图? [英] Python - Fast ploting using pyqtgraph (16ms)?

查看:64
本文介绍了Python - 使用 pyqtgraph (16ms) 快速绘图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用 pyqtgraph 绘制连续输入,因此我使用循环缓冲区来保存数据.我使用带有 maxlen 的 deque 来完成这项工作.(Python 2.7,numpy 1.9.2,pyqtgraph 0.9.10)

I need to plot an continuous input using pyqtgraph, so I use a circular buffer to hold the data. I use deque with maxlen to do the job. (Python 2.7, numpy 1.9.2, pyqtgraph 0.9.10)

from collections import deque
def create_cbuffer(self):
    buffer_len = self.BUFFER_LEN*self.number_of_points
    data = [0]*buffer_len # buffer_len = 160k
    self.cbuffer[0] = deque(data, maxlen=buffer_len)
    buffer_len = self.BUFFER_LEN
    data = [0]*buffer_len
    self.cbuffer[1] = deque(data, maxlen=buffer_len)

之后我是这样使用的:

import time
def update_cbuffer(self):
    data_points, data = data_feeds()  # data get every 16ms as lists
    start_t = time.time()
    self.cbuffer[0].extend(data_points) # Thanks to @PadraicCunningham
    # for k in xrange(0, self.number_of_points):
    #     self.cbuffer[0].append(data_points[k])
    self.cbuffer[1].append(data)
    fin_t = time.time() - start_t

设置图为:

self.curve[0] = self.plots[0].plot(self.X_AXIS, 
                [0]*self.BUFFER_LEN*self.number_of_points,
                pen=pg.intColor(color_idx_0),name='plot1')
self.curve[1] = self.plots[1].plot(self.X_AXIS_2, [0]*self.BUFFER_LEN,
                pen=pg.intColor(color_idx_1),name='plot2')

更新图为:

def update_plots(self):
    self.curve[0].setData(self.X_AXIS, self.cbuffer[0])
    self.curve[0].setPos(self.ptr, 0)
    self.curve[1].setData(self.X_AXIS_2, self.cbuffer[1])
    self.curve[1].setPos(self.ptr, 0)
    self.ptr += 0.016

然后我使用 QTimer 调用它:

Then I call it using QTimer:

self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.update_cbuffer)
self.timer.timeout.connect(self.update_plots)
self.timer.start(16)

问题是:

1.我绘制的时候,好像比16ms慢很多.有什么办法可以加快速度吗?

2. 当我使用 time.time() 对 update_plots() 计时并计算其平均运行时间 (total_time/number_of_runs) 时,它逐渐增加,我试图了解其背后的原因.

有什么建议么?我是 Python 新手,我可能会在代码中犯一些错误,请不要犹豫指出.提前感谢您的帮助.

The Question is:

1. When I plot it, it seems to be much slower than 16ms. Any ideas to speed it up?

2. When I time the update_plots() using time.time() and calculate its average run time (total_time/number_of_runs), it increases gradually, I trying to understand the reason behind it.

Any suggestions? I am new to Python, I could make some mistakes in the code, please do not hesitate to point it out. Thank you for your help in advance.

p.s 我已经按照建议尝试了不同的循环缓冲区高效的循环缓冲区?

p.s I've try different circular buffers as suggested in efficient circular buffer?

class Circular_Buffer():
    def __init__(self, buffer_len, data_type='float'):
        if data_type == 'int':
            self.__buffer = np.zeros(buffer_len, dtype=int)
        else:
            self.__buffer = np.zeros(buffer_len)
        self.__counter = 0

    def append(self, data):
        self.__buffer = np.roll(self.__buffer, -1)
        self.__buffer[-1] = data

    def get(self):
        return self.__buffer

但结果证明在 我的情况.

我也试过这个:

class CB_list():
    def __init__(self, buffer_len):
        self.__buffer = [0]*buffer_len

    def append(self, data):
        self.__buffer = self.__buffer[1:]
        self.__buffer.append(data)

    def get(self):
        return self.__buffer

它的性能类似于 deque,所以我坚持使用 deque.

It performs similar as deque, so I stick with deque.

对不起,我昨天犯了一个错误.我已经在代码上更正了.

Sorry I made a mistake yesterday. I've already correct it on the code.

data = [0]*buffer_len # buffer_len = 16k  <--- Should be 160k instead

推荐答案

我不确定这是一个完整的答案,但信息太长,无法转成评论,我认为这对您理解问题.

I'm not sure this is a complete answer, but the information is too long to turn into a comment, and I think it is critical for your understanding of the problem.

我认为您不太可能让计时器每 16 毫秒触发一次.首先,如果您的方法 self.update_cbufferself.update_plots 运行时间超过 16 毫秒,那么 QTimer 将在应该时跳过触发, 并在下一个 16 ms 的倍数上触发(例如,如果这些方法需要 31 ms 才能运行,则您的计时器应在 32 ms 后触发.如果这些方法需要 33 ms 才能运行,则计时器将在前一个之后的 48 ms 后触发)

I think it is very unlikely you will get your timer to fire every 16 ms. Firstly, if your methods self.update_cbuffer and self.update_plots take longer than 16 ms to run, then the QTimer will skip firing when it should, and fire on the next multiple of 16 ms (eg if the methods take 31 ms to run, your timer should fire after 32 ms. If the methods then take 33 ms to run, the timer will next fire 48 ms after the previous one)

此外,计时器的准确性取决于平台.在 Windows 上,计时器只有 准确到大约 15 毫秒.为了证明这一点,我编写了一个脚本来在我的 Windows 8.1 机器上进行测试(代码包含在文章末尾).此图显示了与预期超时的偏差(以毫秒为单位).

Furthermore, the accuracy of the timer is platform dependent. On windows, timers are only accurate to around 15 ms. As proof of this, I wrote a script to test on my windows 8.1 machine (code included at the end of the post). This graph shows the deviation from the expected timeout in ms.

在这种情况下,我的示例提前了大约 12 毫秒.请注意,这并不完全正确,因为我认为我的代码没有考虑将错误附加到错误列表所需的时间长度.然而,那个时间应该比你在我的图中看到的偏移量少得多,它也没有说明值的大范围传播.简而言之,Windows 上的计时器的准确性与超时大小有关.不是一个好的组合.

In this case, my example was firing around 12ms early. Note that this isn't quite correct, as I don't think my code takes into account the length of time it takes to append the error to the list of errors. However, that time should be much less than the offset you see in my figure, nor does it account for the large spread of values. In short, timers on windows have an accuracy around the size of your timeout. Not a good combination.

希望这至少可以解释为什么代码没有按照您的预期运行.但是,如果没有一个简单的工作示例,或者您自己对代码进行全面的分析,就很难知道速度的瓶颈在哪里.

Hopefully this at least explains why the code isn't doing what you expect. Without a minimilistic working example though, or comprehensive profiling of the code by yourself, it is difficult to know where the bottleneck in speed is.

顺便说一句,当我下面代码中的超时非常小时,pyqtgraph 似乎在一段时间后停止更新我的直方图.不知道为什么会这样.

As a small aside, pyqtgraph seemed to stop updating my histogram after a while when the timeout in my code below was very small. Not sure why that was.

生成上图的代码

from PyQt4 import QtGui, QtCore
import sys
import time
import pyqtgraph as pg
import numpy as np

start_time = time.time()

timeout = 0.16 # this is in SECONDS. Change to vary how often the QTimer fires
time_list = []

def method():
    global start_time
    time_list.append((timeout-(time.time()-start_time))*1000)
    start_time = time.time()

def update_plot():
    y,x = np.histogram(time_list, bins=np.linspace(-15, 15, 40))
    plt1.plot(x, y, stepMode=True, fillLevel=0, brush=(0,0,255,150))

app = QtGui.QApplication(sys.argv)

win = pg.GraphicsWindow()
win.resize(800,350)
win.setWindowTitle('Histogram')
plt1 = win.addPlot()
y,x = np.histogram(time_list, bins=np.linspace(-15, 15, 40))
plt1.plot(x, y, stepMode=True, fillLevel=0, brush=(0,0,255,150))
win.show()

timer = QtCore.QTimer()
timer.timeout.connect(method)
timer.timeout.connect(update_plot)
timer.start(timeout*1000)

sys.exit(app.exec_())

这篇关于Python - 使用 pyqtgraph (16ms) 快速绘图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆