如何使用matplotlib pyqt和Qthread正确终止线程

问题描述 投票:1回答:1

我正在使用PyQt5设计应用程序。有很多图,我使用Matplotlib来管理它们。

当前,我正在尝试使用Qthread,以便Main Loop不会冻结太长时间。

我使用了This exemple: How to use a Qthread to update a Matplotlib figure with PyQt?

但是,正如导师所提到的,在第一个解决方案中,我创建的线程永远不会停止。

我的问题是:在replot对象中完成Plotter()功能后,如何停止它?

我不喜欢在此代码中使用Terminate()

而且QThread完成的事实将使我能够使用PushButton之类的连接来再次设置self.thread.finished.connect(my_function)能力。

这是我的代码的一些简化部分:

创建图的类图

# Figures

class My_figure(FigureCanvas):

    send_fig = QtCore.pyqtSignal(Axes, name="send_fig")

    def __init__(self, fig_size, fig_move, parent=None):
        self.fig = Figure(figsize=fig_size)
        self.axes = self.fig.add_subplot(111)

        FigureCanvas.__init__(self, self.fig)
        self.setParent(parent)
        self.move(fig_move[0], fig_move[1])

    def update_plot(self, axes):
        self.axes = axes
        self.draw()

主对话框中的功能

#  graphs creation
    def new_graph(self, name):

        setattr(self, name + '_my_fig', [])

        # créer les graphs, axes, canvas, etc.
        graph_cat = ['bar_', 'pie_','line_']
        graph_element = ['_figure', '_canvas', '_axes', '_plotter', '_thread']
        fig_dim = [[0, (6.8, 4.3), (6, 3.5)],[0, 0, 30]]
        compt = 0
        for g_c in graph_cat:

            getattr(self, name + '_my_fig').append([])

            setattr(self, g_c + name + '_my_fig', My_figure((3,3),[0,0], parent = getattr(self, g_c + name)))
            getattr(self, name + '_my_fig')[-1].append(getattr(self, g_c + name + '_my_fig'))
            # Couple thread / worker
            setattr(self, g_c + name + graph_element[3], None)
            setattr(self, g_c + name + graph_element[4], None)
            getattr(self, name + '_my_fig')[-1].append(getattr(self, g_c + name + graph_element[3]))
            getattr(self, name + '_my_fig')[-1].append(getattr(self, g_c + name + graph_element[4]))

            compt += 1
# thread and worker creation + start
        for my_fig in self.tot_my_fig:
            print(my_fig)
            # if there is already a thread running, kill it first
            if my_fig[1] != None and my_fig[1].isRunning():
                print('termiante')
                my_fig [1].terminate()

            my_fig[1] = QtCore.QThread()
            my_fig[2] = Plotter()

            self.send_fig.connect(my_fig[2].replot)
            my_fig[2].return_fig.connect(my_fig[0].update_plot)
            my_fig[1].finished.connect(self.ppp)
            #move to thread and start
            my_fig[2].moveToThread(my_fig[1])
            my_fig[1].start()
            # start the plotting
            self.send_fig.emit(my_fig[0].axes)

工人阶级

# Worker

class Plotter(QtCore.QObject):

    return_fig = QtCore.pyqtSignal(Axes)

    @QtCore.pyqtSlot(Axes)
    def replot(self, axes):  # A slot takes no params
        axes.clear()
        # do some random task
        data = np.random.rand(1000,1000)
        axes.plot(data.mean(axis=1))
        self.return_fig.emit(axes)
python multithreading matplotlib pyqt
1个回答
0
投票

我要做的是创建一个绘图线程,然后将要绘制的图形和轴传递到该线程上。当您在一个线程完成之前再次绘图时,两个线程可以同时运行,并且两个线程都完成了,但是最新的线程是显示的。

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys
import random
import time


from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt


class MplFigure(object):
    def __init__(self,parent):
        self.figure=plt.figure(facecolor=(.195,.195,.195))
        self.canvas=FigureCanvas(self.figure)


class plotThread(QThread):
    finished=pyqtSignal()
    def __init__(self,main_figure,ax1,x,y=[]):
        super(plotThread, self).__init__()
        self.main_figure=main_figure
        self.ax1=ax1
        self.x=x
        self.y=y

    def run(self):
        self.ax1.clear()

        line,=self.ax1.plot(self.x)
        #line.set_ydata(self.y)
        self.ax1.draw_artist(line)
        self.main_figure.canvas.draw()
        time.sleep(2)
        self.finished.emit()

WINDOW_SIZE=900,600

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300,300,*WINDOW_SIZE)
        layout=QVBoxLayout()
        view=QGraphicsView()
        view.setLayout(layout)
        self.main_figure=MplFigure(self)
        layout.addWidget(self.main_figure.canvas)
        self.setCentralWidget(view)
        self.ax1=self.main_figure.figure.add_subplot(1,1,1)
        self.btn=QPushButton('Plot Random')
        layout.addWidget(self.btn)
        self.btn.clicked.connect(self.plot_threaded)
        self.show()

    def plot_threaded(self):
        #self.btn.setEnabled(False)
        rand=random.sample(range(1,20),10)
        self.worker=plotThread(self.main_figure,self.ax1,rand)
        self.worker.finished.connect(self.enable_button)
        self.worker.start()

    def enable_button(self):
        #self.btn.setEnabled(True)
        print('Thread finished')


if __name__=='__main__':
    app=QApplication([])
    window=MainWindow()
    app.exec_()
    sys.exit()
© www.soinside.com 2019 - 2024. All rights reserved.