第一个问题是,
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_())
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)