在 PyQt4 中使用 PyQtGraph 进行实时绘图

Posted

技术标签:

【中文标题】在 PyQt4 中使用 PyQtGraph 进行实时绘图【英文标题】:Live Plotting with PyQtGraph in PyQt4 【发布时间】:2017-05-31 10:47:09 【问题描述】:

我是 Python 的新手,正在尝试制作一个 PyQt4 应用程序,我将 PyQtGraph 嵌入其中。我有这个 PyQtGraph 实时绘图仪,效果非常好:

from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import random

app = QtGui.QApplication([])
p = pg.plot()
curve = p.plot()
data = [0]

def updater():

    data.append(random.random())
    curve.setData(data) #xdata is not necessary


timer = QtCore.QTimer()
timer.timeout.connect(updater)
timer.start(0)

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

为了嵌入更大的 PyQt4 应用程序,我需要一个包含 pyqtgraph.PlotWidget() 的布局。为此,我在 MainWindow 中设置了一个 centralWidget。我创建了一个按钮,它应该像前面的代码一样开始绘图,但是当我通过绘图仪函数调用更新器函数时什么也没发生:

import sys
from PyQt4 import QtCore, QtGui
import pyqtgraph as pg
import random

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.central_widget = QtGui.QStackedWidget()
        self.setCentralWidget(self.central_widget)
        login_widget = LoginWidget(self)#to say where the button is
        login_widget.button.clicked.connect(self.plotter)
        self.central_widget.addWidget(login_widget)

    def plotter(self):
        self.data =[0]
        timer = QtCore.QTimer()
        timer.timeout.connect(self.updater)
        timer.start(0)

    def updater(self):

        self.data.append(random.random())
        plot.setData(self.data)

class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        global plot
        super(LoginWidget, self).__init__(parent)
        layout = QtGui.QHBoxLayout()
        self.button = QtGui.QPushButton('Start Plotting')
        layout.addWidget(self.button)
        plot = pg.PlotWidget()
        layout.addWidget(plot)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

因为我必须穿线,所以什么都没有发生?

【问题讨论】:

【参考方案1】:

代码中有几件事情需要考虑。 首先,与@luddek 的回答方向相同,您需要跟踪变量。如果您在类方法中定义了一个变量,并且该类方法执行完毕,则该变量将丢失。从外面也看不到。 因此,最好使用实例变量,self.plot 代替 plotself.timer 代替 timerself.login_widget 代替 login_widget (另外,我不建议在 PyQt 程序中使用 global,尽管它是有效代码)

接下来,PlotWidget 没有 setData 方法。将数据绘制到 PlotItem 的绘图中涉及更多一点:pg.PlotWidget() 有一个 PlotItem,您可以通过 .getPlotItem() 获得它。然后你需要在它上面调用plot(),它会返回你想要添加数据的实际曲线。在下面的示例中,我介绍了新变量self.curve,您可以通过self.curve.setData(self.data)向其中添加数据

这是完整的工作代码。

from PyQt4 import QtCore, QtGui
import pyqtgraph as pg
import random

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.central_widget = QtGui.QStackedWidget()
        self.setCentralWidget(self.central_widget)
        self.login_widget = LoginWidget(self)
        self.login_widget.button.clicked.connect(self.plotter)
        self.central_widget.addWidget(self.login_widget)

    def plotter(self):
        self.data =[0]
        self.curve = self.login_widget.plot.getPlotItem().plot()

        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updater)
        self.timer.start(0)

    def updater(self):

        self.data.append(self.data[-1]+0.2*(0.5-random.random()) )
        self.curve.setData(self.data)

class LoginWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(LoginWidget, self).__init__(parent)
        layout = QtGui.QHBoxLayout()
        self.button = QtGui.QPushButton('Start Plotting')
        layout.addWidget(self.button)
        self.plot = pg.PlotWidget()
        layout.addWidget(self.plot)
        self.setLayout(layout)

if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

【讨论】:

非常感谢@ImportanceOfBeingErnest,我真的在努力让我的变量范围理解启动并运行,但这需要我一些时间。幸运的是,你们是热情的程序员 :-) 我也没有在文档中找到正确使用 pg.PlotWidget() .....再次感谢! 如果这解决了您的问题,请考虑accepting it。如果不能随意改进您的问题。【参考方案2】:

updater() 未被调用,因为计时器已被垃圾收集器移除。

您需要在某处保留对计时器的引用。例如,您可以在 __init__ 中创建引用

def __init__(self, parent=None):
    ...
    self.timer = QtCore.QTimer()

【讨论】:

虽然这是正确的,但防止计时器被垃圾收集只是整个问题的一部分。

以上是关于在 PyQt4 中使用 PyQtGraph 进行实时绘图的主要内容,如果未能解决你的问题,请参考以下文章

Pyqt4-pyqtgraph 应用程序递归打开自身的新实例

pyqtgraph删除pyqt4 gui中的持久图例

PyQt4 中的 QThreading PyQtGraph PlotWidgets

在 PyQtGraph 中反转 Y 轴

PyQtGraph 图在 Qt MainWindow 上显示不正确

pyqtgraph 轴未正确显示