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

标签 python multithreading matplotlib pyqt

我正在使用 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)

# 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)

编辑:

我找到了答案,感谢https://stackoverflow.com/a/6789205/12016306

我只需要在工作人员完成时发送一个信号并将该信号连接到 quit()线程的方法。像这样:

class Worker(QObject):

    finished = pyqtSignal()

    def do_the_work(self):
        # do the long task and even the plotting
        self.finished.emit()

class MainWindow(QMainWindow):

    def __init__(self):
        #Normal init goes here

        #construction of the thread and worker
        self.worker = Worker()
        self.thread = Qthread()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.do_the_work)
        self.worker.finished.connect(self.thread.quit)
        self.thread.finished.connect(self.print_when_finished)
        self.thread.start() # You can start it whenever you want. Put it in a function to start the worker only after a certain action.

最佳答案

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

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

关于python - 如何使用 matplotlib pyqt 和 Qthread 正确终止线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59257507/

相关文章:

python - 在 matplotlib 中,我如何绘制一条多色线,如彩虹

python - 在 python pandas 中使用两个不同的数据集生成散点图

python - 在 nestedExpr 中保留换行符

c++ - OpenGL - 在 ubuntu 中的线程上创建 vbo?

c - 如何将服务器中的一些数据写入连接到我的服务器的所有客户端?

matplotlib - 在 julia 中使用 matplotlib 的补丁

python - 如何在过滤器查询sqlalchemy中动态 "_or"

java - 我正在尝试制作一个非常基本的计算器,可以使用一个输入,但我有点挣扎

python - 如何使用正则表达式将所有重复的标点符号替换为单个标点符号?

c# - 数据绑定(bind)、多线程和单元测试