我正在尝试将一些代码从使用matplotlib转换为pyqtgraph,因为它被认为更加高效,并提供了更多的交互特性。我已经将代码大部分转换完成,但是在运行时遇到了运行缓慢的问题。以下是一些重现此问题的代码:
import numpy as np
import qtpy.QtWidgets as qt
import pyqtgraph as pg
class GraphWidget(qt.QWidget):
"""A widget for simplifying graphing tasks
:param qt.QWidget parent:
:param Dict[str, dict] layout: A mapping from title to row/col/rowspan/colspan kwargs
"""
def __init__(self, parent, layout_spec):
super(GraphWidget, self).__init__(parent=parent)
self.axes = {}
glw = pg.GraphicsLayoutWidget(parent=self)
for name, layout in layout_spec.items():
self.axes[name] = pg.PlotItem(name=name, title=name)
glw.addItem(self.axes[name], **layout)
box_layout = qt.QVBoxLayout()
box_layout.addWidget(glw, 1)
self.setLayout(box_layout)
@property
def normal_pen(self):
return pg.mkPen(color='w', width=2)
@property
def good_pen(self):
return pg.mkPen(color='g', width=2)
@property
def bad_pen(self):
return pg.mkPen(color='r', width=2)
def plot(self, mode, x, y, axis):
if mode == 'normal':
pen = self.normal_pen
elif mode == 'good':
pen = self.good_pen
elif mode == 'bad':
pen = self.bad_pen
plot_item = pg.PlotCurveItem(x, y, pen=pen)
self.axes[axis].addItem(plot_item)
if __name__ == '__main__':
import random
import time
# qt.QApplication.setGraphicsSystem('opengl')
app = qt.QApplication([])
window = qt.QWidget(parent=None)
layout = qt.QVBoxLayout()
gw = GraphWidget(
window,
{
'A': dict(row=1, col=1, rowspan=2),
'B': dict(row=1, col=2),
'C': dict(row=2, col=2),
'D': dict(row=1, col=3),
'E': dict(row=2, col=3),
'F': dict(row=1, col=4),
'G': dict(row=2, col=4),
}
)
layout.addWidget(gw, 1)
def plot():
start = time.time()
for axis in 'ABCDEFG':
gw.plot(
random.choice(['normal', 'good', 'bad']),
np.arange(2000),
np.random.rand(2000),
axis,
)
# necessary because without it, the "plotting" completes in ms,
# but the UI doesn't update for a while still
app.processEvents()
print('Plotting time: {}'.format(time.time() - start))
button = qt.QPushButton(parent=window, text='Plot')
button.pressed.connect(plot)
layout.addWidget(button)
window.setLayout(layout)
window.showMaximized()
app.exec_()
我选择的图形数量、布局和点数反映了实际使用情况。如果我按原样运行并点击两次绘图按钮,我会看到
Plotting time: 3.61599993706
Plotting time: 7.04699993134
我在这个点上停止了,因为整个应用程序突然变得非常缓慢,需要几秒钟才能关闭。如果我取消注释启用OpenGL渲染的一行代码,我可以轻松地运行它多次,看起来……
Plotting time: 0.0520000457764
Plotting time: 0.328999996185
Plotting time: 0.453000068665
Plotting time: 0.55999994278
Plotting time: 0.674000024796
Plotting time: 1.21900010109
Plotting time: 0.936000108719
Plotting time: 1.06100010872
Plotting time: 1.19899988174
Plotting time: 1.35100007057
在这一点上,我也可以告诉你这里报告的时间并不真实准确,UI实际反映更新所需的时间比这些时间更长。
对于我来说,这是一个相当典型的图形数量,该应用程序可以轻松地在大约20秒内查看16组图形(每个轴增加一条额外线路)。如果我的UI变得越来越慢,那么这就不够快了。
与PlotDataItem不同,Down-sampling似乎不适用于PlotCurveItem,但我发现进行以下操作:
plot_item = pg.PlotCurveItem(x, y, pen=pen, connect='pairs')
优化后可以显著提高速度:
Plotting time: 0.0520000457764
Plotting time: 0.0900001525879
Plotting time: 0.138000011444
Plotting time: 0.108000040054
Plotting time: 0.117000102997
Plotting time: 0.12299990654
Plotting time: 0.143000125885
Plotting time: 0.15499997139
虽然如此,我仍然认为速度很慢,我想知道是否有任何方法可以进一步加快它。如果我不设置opengl,它仍然非常缓慢(每个图形需要几秒钟时间)。我真的希望能够尽可能快地绘制图像。我的目标是每个图形少于100毫秒。
然而很难确定哪里会出现延迟,对这段代码进行分析似乎很困难,因为其中一些发生在OpenGL级别,一些深入Qt代码,还有一些在pyqtgraph本身内部。
还有其他方法可以进一步加快此代码吗?
注意:我目前正在使用Python 2.7 64位、PyQt 4.10.4和通过conda安装的pyqtgraph 0.10.0,但此代码需要在Python 3.5+上同样良好地工作。
self.axes[axis].clear()
),则绘图时间保持不变。 - titusjan