在 PyQt4 #2 中使用 PyQtGraph 进行实时绘图
Posted
技术标签:
【中文标题】在 PyQt4 #2 中使用 PyQtGraph 进行实时绘图【英文标题】:Live Plotting with PyQtGraph in PyQt4 #2 【发布时间】:2017-06-02 18:57:55 【问题描述】:首先对篇幅表示抱歉。我想尽可能地解释我的问题。我对 Python 很陌生,并试图使用嵌入在 PyQt4 中的 PyQtGraph 制作一个绘图应用程序。几天前,我的plotting problem 得到了一个非常好的答案,我的下一步是让两个 PyQtGraphs 绘图小部件同时在同一个 PyQt4 的 CentralWidget 中绘图。通过与描述的链接相同的方法,两个图都可以正常工作,但是 GUI 没有响应。为了克服这个问题,我的目标是使用QThread,为此,我需要在不同的类中使用我的绘图功能。但是我弄乱了我的变量,看不到如何:
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(Plots.plotter)
self.central_widget.addWidget(self.login_widget)
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)
class Plots(MainWindow):
def print(self):
print('hello World')
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)
if __name__ == '__main__':
app = QtGui.QApplication([])
window = MainWindow()
window.show()
app.exec_()
这给了我一个 Plots.plotter 错误:
self.data = [0]
AttributeError: 'bool' object has no attribute 'data'
如果在 MainWindow 类中我将“button.connect”参数替换为 Plots.print,它可以正常工作。所以我可以看到我在 MainWindow 中创建了一个 LoginWidget 对象,然后 Plots 从 MainWindow 继承,再次调用相同的 LoginWidget 对象这一事实有问题。
我尝试了一个建议的解决方案,其中父亲(MainWindow)不访问孩子(Plots)的方法。但是,如果从 Plots 中,我想调用我打算放置线程的类,我会再次遇到同样的错误....
import sys
from PyQt4 import QtCore, QtGui
import pyqtgraph as pg
import random
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)
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.central_widget.addWidget(self.login_widget)
class Plots(MainWindow):
def __init__(self, parent=None):
super(Plots, self).__init__(parent=parent)
self.login_widget.button.clicked.connect(MyThread.plotter)
class MyThread(MainWindow):
def __init__(self, parent=None):
super(Aname, self).__init__(parent=parent)
def print(self):
print('hello World')
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)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = Plots()
w.show()
sys.exit(app.exec_())
【问题讨论】:
您的代码给了我一个不同的错误。self.login_widget.button.clicked.connect(Plots.plotter)
AttributeError: 'function' 对象没有属性 'pyqtSignature'
当您在 self.login_widget.button.clicked.connect(Plots.plotter) 中将 Plots.plotter 替换为 Plots.print 时是否会出现相同的错误?
【参考方案1】:
在继承中,父类不应该访问子类的方法,最好在子类中继承和实现与父类无关的新方法。
定时器版本
import random
import sys
import pyqtgraph as pg
from PyQt4 import QtGui, QtCore
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)
self.button.clicked.connect(self.plotter)
def plotter(self):
self.data = [0]
self.curve = self.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 MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.centralwidget = QtGui.QWidget(self)
self.setCentralWidget(self.centralwidget)
self.horizontalLayout = QtGui.QHBoxLayout(self.centralwidget)
self.login_widget_1 = LoginWidget(self)
self.horizontalLayout.addWidget(self.login_widget_1)
self.login_widget_2 = LoginWidget(self)
self.horizontalLayout.addWidget(self.login_widget_2)
self.setCentralWidget(self.centralwidget)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
【讨论】:
谢谢,但这并不能解决我的问题。 “我需要在不同的类中拥有我的绘图功能”,才能使用 QThread。所以,如果我只是创建一个同样从 MainWindow 继承的新类并调用它,我会得到同样的错误。在这种情况下,我不会将我的插槽调用位置放在我继承的类(MainWindow)中,而是在 Plots 中,正如你所建议的那样。 @Ivy 你能放一张你想要的照片吗? 我希望在同一个小部件中包含两个按钮和两个图表。每个按钮都会触发一个图表,就像上面的单个图表示例一样,并且应用程序仍然是响应式的,就像上面的单个图表示例一样。 @Ivy 要使用线程,不必有不同的类。 谢谢@eyllanesc,我很感激。线程看起来很有趣:GUI 是响应式的! :-) 但它会以不同的延迟更新,并且其中一个线程在短时间内被销毁。我将在 QThread 上工作以使其正常工作。以上是关于在 PyQt4 #2 中使用 PyQtGraph 进行实时绘图的主要内容,如果未能解决你的问题,请参考以下文章
PyQt4 中的 QThreading PyQtGraph PlotWidgets
Pyqt4-pyqtgraph 应用程序递归打开自身的新实例