我正在使用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阵列是一个好策略吗?是否有更好的方法来更新数据,因为我只更改了每行的几个值(添加一个点并可能删除一两个点)?