qpython怎么用matplotlib_如何使用Qthread使用PyQt更新Matplotlib图?

第一个问题是,一旦启动线程,就会丢失对线程的引用.保持引用使用类变量,即self.thread而不是thread.

接下来,必须在执行任何操作之前启动线程.所以你需要将self.thread.start()放在信号发射之前.

现在,它已经可以工作了,但是一旦你想要开始一个新线程就会出现下一个问题.所以,你需要先杀死旧的.由于旧的绘图仪将无家可归,因此解决方案是每次要绘制时创建新的绘图仪以及新线程.这是以下解决方案的工作方式.

或者,您也可以始终使用相同的绘图仪和线程.唯一要记住的是,总有一个工人(绘图仪)和一个线程,如果你删除其中一个,另一个是悲伤的.

为了测试它,我需要改变一些小东西,比如使用PyQt4代替5并替换数据生成.

这是工作代码.

from PyQt4.QtCore import *

from PyQt4.QtGui import *

from matplotlib.axes._subplots import Axes

from matplotlib.figure import Figure

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

import sys

from datetime import datetime, timedelta

import numpy as np

class 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_())

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

from PyQt4.QtCore import *

from PyQt4.QtGui import *

from matplotlib.figure import Figure

from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas

import sys

import numpy as np

class 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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值