Python PySide2和Matplotlib:如何使Matplotlib在单独的进程中运行。。因为它不能在单独的线程中运行

Python PySide2和Matplotlib:如何使Matplotlib在单独的进程中运行。。因为它不能在单独的线程中运行,python,matplotlib,multiprocessing,pyside2,Python,Matplotlib,Multiprocessing,Pyside2,我不是一个有经验的程序员,我正在尝试使用qtforpython(PySide2)在python中创建一种数据记录器程序来构建GUI。我能够使用Designer创建gui,并在python中加载它。gui目前只是一个空白窗口。然后,我创建了一个函数,在一个显示图形的窗口中启动MatplotLib,并使用Qt计时器更新主程序每个循环中的数据 所有这些都可以工作,但是MatPlotLib的重画时间太慢了gui刷新。所以我试着把MatPlotLib放在一个separe线程中,经过多次尝试,我明白它不能在

我不是一个有经验的程序员,我正在尝试使用qtforpython(PySide2)在python中创建一种数据记录器程序来构建GUI。我能够使用Designer创建gui,并在python中加载它。gui目前只是一个空白窗口。然后,我创建了一个函数,在一个显示图形的窗口中启动MatplotLib,并使用Qt计时器更新主程序每个循环中的数据

所有这些都可以工作,但是MatPlotLib的重画时间太慢了gui刷新。所以我试着把MatPlotLib放在一个separe线程中,经过多次尝试,我明白它不能在一个单独的线程中运行。。 最后,我决定尝试多处理。现在MatPlotLib在一个单独的进程中运行良好(我使用队列将数据发送到MatPlotLib),并在进程完成后正确退出,但当我关闭主窗口时,程序将完全关闭,同时键入Ctrl+C时,提示将被阻止

这是我的代码:

#!/usr/bin/env python3
import sys
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QWidget
from PySide2.QtCore import QFile, QTimer

import matplotlib.pyplot as plt
from multiprocessing import Process, Queue, freeze_support
import random


class DSL(QWidget):
    def __init__(self):
        # LOAD HMI
        QWidget.__init__(self)
        designer_file = QFile('userInterface.ui')
        designer_file.open(QFile.ReadOnly)
        loader = QUiLoader()
        self.ui = loader.load(designer_file, self)
        designer_file.close()
        self.ui.show()

        # Data to be visualized
        self.data = []

    def mainLoop(self):
        self.data = []
        for i in range(10):
            self.data.append(random.randint(0, 10))

        # Send data to graph process
        queue.put(self.data)

        # LOOP repeater
        QTimer.singleShot(10, self.mainLoop)


def graphProcess(queue):
    for i in range(10):
        # Get data
        data = queue.get()

        # MatPlotLib
        plt.ion()
        plt.clf()
        plt.plot(data)
        plt.show()
        plt.pause(0.1)

    print('process end')


if __name__ == '__main__':
    # MatPlotLib Process
    queue = Queue()
    freeze_support()
    p = Process(target=graphProcess, args=(queue,))
    p.daemon = True
    p.start()

    # PySide2 Process
    app = QApplication(sys.argv)
    dsl = DSL()
    dsl.mainLoop()
    sys.exit(app.exec_())

与其在辅助进程中使用matplotlib,不如在QWidget中嵌入画布,使其能够在相同的PySide2进程中运行:

#/usr/bin/env蟒蛇3
导入系统
从PySide2.QtCore导入QFile、QObject、信号、插槽、QTimer
从PySide2.QtWidgets导入QApplication、QVBoxLayout、QWidget
从PySide2.QtUiTools导入QUiLoader
将matplotlib.pyplot作为plt导入
从matplotlib.backends.backend_qt5agg导入FigureCanvas qtagg as FigureCanvas
从matplotlib.backends.backend_qt5agg导入导航工具栏2qt作为导航工具栏
从matplotlib.figure导入图形
随机输入
DSL类(QObject):
数据更改=信号(列表)
def uuu init uuu(self,parent=None):
#加载人机界面
super()。\uuuu init\uuuu(父级)
designer_file=QFile(“userInterface.ui”)
如果设计器_file.open(QFile.ReadOnly):
加载器=QUiLoader()
self.ui=loader.load(设计器文件)
设计器_文件.close()
self.ui.show()
#要可视化的数据
self.data=[]
def主回路(自):
self.data=[]
对于范围(10)内的i:
self.data.append(random.randint(0,10))
#将数据发送到图形
self.dataChanged.emit(self.data)
#环路中继器
QTimer.singleShot(10,自主循环)
类MatplotlibWidget(QWidget):
def uuu init uuu(self,parent=None):
super()。\uuuu init\uuuu(父级)
fig=图(figsize=(7,5),dpi=65,facecolor=(1,1,1),edgecolor=(0,0,0))
self.canvas=FigureCanvas(图)
self.toolbar=导航工具栏(self.canvas,self)
lay=QVBoxLayout(自身)
lay.addWidget(self.toolbar)
lay.addWidget(self.canvas)
self.ax=图add_子批次(111)
self.line,*.=self.ax.plot([])
@插槽(列表)
def更新图(自身、数据):
self.line.set_数据(范围(len(数据)),数据)
自身最大设置(0,len(数据))
自最大设定值(最小值(数据)、最大值(数据))
self.canvas.draw()
如果名称=“\uuuuu main\uuuuuuuu”:
app=QApplication(sys.argv)
dsl=dsl()
dsl.mainLoop()
matplotlib_widget=MatplotlibWidget()
matplotlib_widget.show()
dsl.dataChanged.connect(matplotlib\u小部件.update\u plot)
sys.exit(app.exec_())

Hi eyllanesc,非常感谢您的快速回答,这是我第一次使用stackoverflow,我非常高兴它的帮助。你写的代码工作得很好,这对我来说是一个很大的进步。我有一些问题要问你,让你做出选择:-我的chioce不适合你吗?(为了了解我的错误…)-是否可以同时在图形中绘制更多的线(我需要两条)-我使用matplotlib_widget.show()使用按钮再次显示关闭的绘图窗口,对吗?-为什么如果我关闭主窗口,图形会继续绘制?@Emilio 1)我不会指出它是否正确,但正如您所看到的,还有另一个更简单的选项。2) 如果可以绘制任何绘图,在以下链接中有一个示例:,3)是的,它是正确的,代码必须是:
your\u按钮。单击。连接(matplotlib\u widget.show)
4)尝试使用此功能的链接示例/-----问题------------/\n不幸的是,在深入测试您的代码时,我遇到了与第一次实现相同的问题,即创建绘图的代码仅存在于DSL类的一个函数中。。如果你放的越多,点数就越多(比如1000+),整个程序包括主GUI都会变慢。这是因为正如你所说,两个窗口都在同一个进程中。这就是我试图避免多重处理的原因。在尝试多重处理之前,我的代码是:@Emilio问题是你的for循环很耗时,检查链接的更新内容,你会发现它也会这样做,但效率更高。总之,分析瓶颈在哪里,并尝试改进它,不要责怪代码的另一部分。