如何使用Qthread通过PyQt更新Matplotlib图形?

如何使用Qthread通过PyQt更新Matplotlib图形?,第1张

如何使用Qthread通过PyQt更新Matplotlib图形?

第一个问题是,

thread
一旦启动,您将丢失对它的引用。要保留引用,请使用类变量,即
self.thread
代替
thread

接下来,必须在执行任何 *** 作之前启动线程。因此,您需要将

self.thread.start()
信号发射放在前面。

现在,它已经可以工作了,但是一旦您要启动新线程,就会出现下一个问题。因此,您需要先杀死旧的。由于旧的

Plotter
将无家可归,因此一个解决方案是每次要绘制时都创建一个新的Plotter以及一个新线程。这是下面的解决方案的工作方式。
另外,您也可以始终使用相同的绘图仪和线程。唯一要记住的是,始终只有一个工作程序(绘图仪)和一个线程,如果删除其中一个,则另一个很可悲。

为了测试它,我需要更改一些小东西,例如使用PyQt4而不是5并替换数据生成。这是工作代码。

from PyQt4.QtCore import *from PyQt4.QtGui import *from matplotlib.axes._subplots import Axesfrom matplotlib.figure import Figurefrom matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvasimport sysfrom datetime import datetime, timedeltaimport numpy as npclass MyMplCanvas(FigureCanvas):    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""    send_fig = pyqtSignal(Axes, str, name="send_fig")    def __init__(self, parent=None):        self.fig = Figure()        self.axes = self.fig.add_subplot(111)        # We want the axes cleared every time plot() is called        self.axes.hold(False)        FigureCanvas.__init__(self, self.fig)        self.setParent(parent)        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)        FigureCanvas.updateGeometry(self)    def update_plot(self, axes):        self.axes = axes        self.draw()class MainWindow(QMainWindow):    send_fig = pyqtSignal(Axes, str, name="send_fig")    def __init__(self):        super(MainWindow, self).__init__()        self.main_widget = QWidget(self)        self.myplot = MyMplCanvas(self.main_widget)        self.editor = QLineEdit()        self.display = QLabel("Vide")        self.layout = QGridLayout(self.main_widget)        self.layout.addWidget(self.editor)        self.layout.addWidget(self.display)        self.layout.addWidget(self.myplot)        self.main_widget.setFocus()        self.setCentralWidget(self.main_widget)        self.move(500, 500)        self.show()        self.editor.returnPressed.connect(self.updatePlot)        # plotter and thread are none at the beginning        self.plotter = None         self.thread = None    def updatePlot(self):        ticker = self.editor.text()        self.editor.clear()        self.display.setText(ticker)        # if there is already a thread running, kill it first        if self.thread != None and self.thread.isRunning(): self.thread.terminate()        # initialize plotter and thread        # since each plotter needs its own thread        self.plotter = Plotter()        self.thread = QThread()        # connect signals        self.send_fig.connect(self.plotter.replot)        self.plotter.return_fig.connect(self.myplot.update_plot)        #move to thread and start        self.plotter.moveToThread(self.thread)        self.thread.start()        # start the plotting        self.send_fig.emit(self.myplot.axes, ticker)class Plotter(QObject):    return_fig = pyqtSignal(Axes)    @pyqtSlot(Axes, str)    def replot(self, axes, ticker):  # A slot takes no params        print(ticker)        d = datetime.today() - timedelta(weeks=52)  # data from 1week ago        # do some random task        data = np.random.rand(10000,10000)        axes.plot(data.mean(axis=1))        self.return_fig.emit(axes)if __name__ == '__main__':    app = QApplication(sys.argv)    win = MainWindow()    sys.exit(app.exec_())

这是提到的第二个选项的解决方案,即创建单个工作程序和线程,并在程序的整个运行时使用它们。

from PyQt4.QtCore import *from PyQt4.QtGui import *from matplotlib.figure import Figurefrom matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvasimport sysimport numpy as npclass MyMplCanvas(FigureCanvas):    def __init__(self, parent=None):        self.fig = Figure()        self.axes = self.fig.add_subplot(111)        # plot empty line         self.line, = self.axes.plot([],[], color="orange")        FigureCanvas.__init__(self, self.fig)        self.setParent(parent)        FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)        FigureCanvas.updateGeometry(self)class MainWindow(QMainWindow):    send_fig = pyqtSignal(str)    def __init__(self):        super(MainWindow, self).__init__()        self.main_widget = QWidget(self)        self.myplot = MyMplCanvas(self.main_widget)        self.editor = QLineEdit()        self.display = QLabel("Vide")        self.layout = QGridLayout(self.main_widget)        self.layout.addWidget(self.editor)        self.layout.addWidget(self.display)        self.layout.addWidget(self.myplot)        self.main_widget.setFocus()        self.setCentralWidget(self.main_widget)        self.show()        # plotter and thread are none at the beginning        self.plotter = Plotter()        self.thread = QThread()        # connect signals        self.editor.returnPressed.connect(self.start_update)        self.send_fig.connect(self.plotter.replot)        self.plotter.return_fig.connect(self.plot)        #move to thread and start        self.plotter.moveToThread(self.thread)        self.thread.start()    def start_update(self):        ticker = self.editor.text()        self.editor.clear()        self.display.setText(ticker)        # start the plotting        self.send_fig.emit(ticker)    # Slot receives data and plots it    def plot(self, data):        # plot data        self.myplot.line.set_data([np.arange(len(data)), data])        # adjust axes        self.myplot.axes.set_xlim([0,len(data) ])        self.myplot.axes.set_ylim([ data.min(),data.max() ])        self.myplot.draw()class Plotter(QObject):    return_fig = pyqtSignal(object)    @pyqtSlot(str)    def replot(self, ticker):        print(ticker)        # do some random task        data = np.random.rand(10000,10000)        data = data.mean(axis=1)        self.return_fig.emit(data)if __name__ == '__main__':    app = QApplication(sys.argv)    win = MainWindow()    sys.exit(app.exec_())


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4908177.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-12
下一篇 2022-11-12

发表评论

登录后才能评论

评论列表(0条)

保存