使用pyqtgraph在Python中实时绘图

时间:2014-05-06 22:23:42

标签: python qt python-2.7 pyqtgraph

我正在使用Qt(目前为PyQt)在Python中编写应用程序,该应用程序通过UDP接收遥测(位置数据)并显示该数据。它可以处理多种数据包类型,每种类型包含多个数据字段。我有一个单独的线程来处理接收和解码数据包,它们发出一个信号将该数据发送到Qt GUI进行显示。数据以多种方式显示:当前值显示,滚动日志显示和3D视图显示。所有这些都能很好地实时运行,每个数据包的更新频率最高可达30Hz。

我想添加另一个显示实时情节的标签。用户可以选择要绘制的数据流,并且它将实时更新,显示最后60秒数据的滑动窗口(可能在某个时间点可配置)。然而,我的第一种方法特别慢。我们的模拟器运行速度比30Hz慢得多,几乎不能只绘制一条线。

我正在使用pyqtgraph进行绘图。我在我的.ui文件中实例化了一个PlotWidget,并为可以在绘图上绘制的每个数据行创建一个PlotDataItem。我使用deques来存储要绘制的数据,包括值和时间。通过这种方式,我可以快速添加数据,并在数据落在滑动窗口之外时将其删除。我将所有这些存储在每个数据包类型和字段的dict中:

    self.plotData[pktType][field] = {}
    self.plotData[pktType][field]['curve'] = self.pwPlot.plot()
    self.plotData[pktType][field]['starttime'] = time
    self.plotData[pktType][field]['data'] = coll.deque()
    self.plotData[pktType][field]['realtime'] = coll.deque()
    self.plotData[pktType][field]['time'] = coll.deque()

'starttime'存储计算经过的秒数的初始日期时间值。 'realtime'存储每个数据包收到时的日期时间值(我目前没有使用它,所以如果可以节省时间我可以删除它)。 “时间”存储从“开始时间”经过几秒钟,以便于绘图,“数据”存储值。

当一个数据包进来时,我将数据存储在我可能要解析的每个字段的deques中。然后我剪掉滑动窗口外的任何数据。最后,deque被打包在一个numpy数组中并传递给PlotDataItem setData方法。以下是为每个接收到的数据包运行的代码的简化版本:

def updatePlot(self, time, pktData):
    pktType = pktData['ptype']

    keys = self.getPlottableFromType(pktType) # list of fields that can be plotted
    if keys == None:
        return
    for k in keys:
        self.plotData[pktType][k]['data'].append(pktData[k])
        self.plotData[pktType][k]['realtime'].append(time)
        runtime = (time - self.plotData[pktType][k]['starttime']).total_seconds()
        if self.plotRate == 0:
            self.plotData[pktType][k]['time'].append(runtime)
        else:
            if self.plotData[pktType][k]['time']: # has items
                nexttime = self.plotData[pktType][k]['time'][-1] + 1. / self.plotRate
            else:
                nexttime = 0

            self.plotData[pktType][k]['time'].append(nexttime)

        while (self.plotData[pktType][k]['time'][-1] - self.plotData[pktType][k]['time'][0]) > self.plotRangeSec:
            self.plotData[pktType][k]['data'].popleft()
            self.plotData[pktType][k]['realtime'].popleft()
            self.plotData[pktType][k]['time'].popleft()

        self.drawPlot(pktType, k)

def drawPlot(self, pktType, k):
    if self.plotIsEnabled(pktType, k) and self.plotData[pktType][k]['time']: # has items
        npt = np.array(self.plotData[pktType][k]['time'])
        npd = np.array(self.plotData[pktType][k]['data'])
        self.plotData[pktType][k]['curve'].setData(npt, npd)
    else:
        self.plotData[pktType][k]['curve'].clear()

self.plotRate可用于使用挂起时间绘制数据或将时间轴强制为固定更新速率。这对于与仿真器一起使用很有用,因为它比实际系统运行得慢。

我应该做的第一件事就是每次都没有调用.clear()那些没有被绘制的图(只是使逻辑复杂一点)。除此之外,任何人都有任何提高性能的技巧? deque到numpy阵列是一个好策略吗?是否有更好的方法来更新数据,因为我只更改了每行的几个值(添加一个点并可能删除一两个点)?

0 个答案:

没有答案