为什么 pyplot window 从独立函数生成与从事件处理程序调用的函数生成时表现不同?

Why does a pyplot window behave differently when it is generated from a stand-alone function vs. a function called from an event handler?

当我 运行 我的 setup_plotdataq 独立运行时,pyplot window 的行为符合预期,即在 运行 完成按钮后导航工具栏中的(pan/zoom 等)处于活动状态。但是,当我导入函数并从主程序中的按钮事件处理程序调用它们时,pyplot window 在 运行 完成后保持活动状态:它仍在接受数据并且工具栏按钮处于非活动状态。我应该如何在不关闭绘图的情况下停止绘图window?这是一个片段:

class MyWindowClass(QtGui.QWidget, form_class):
    def __init__(self, parent=None):
       QtGui.QWidget.__init__(self, parent)
       self.setupUi(self)
       self.pushButton_Run.clicked.connect(self.pushbutton_run_clicked)
       self.pushButton_Stop.clicked.connect(self.pushbutton_stop_clicked)

    def pushbutton_run_clicked(self):
        # get line edit values here 
        functions.setup_plot()
        functions.dataq(steptime, runtime, CO2_1, CO2_2)

我试图通过根据您提供给我们的代码片段创建一个简单的 MCVE 来重现您的问题。如果我不将 matplotlib 的 backend 设置为 Qt4Agg.

,我能找到的唯一能让我的简单应用程序按照您描述的方式运行的方法
from PyQt4 import QtGui
import sys
import numpy as np

import matplotlib as mpl
mpl.use('Qt4Agg')
import matplotlib.pyplot as plt

class MyWindowClass(QtGui.QWidget):
    def __init__(self, parent=None):
       super(MyWindowClass, self).__init__(parent)

       pushButton_Run = QtGui.QPushButton('Run')
       pushButton_Run.clicked.connect(self.pushbutton_run_clicked)

       layout = QtGui.QGridLayout()
       layout.addWidget(pushButton_Run, 0, 0)
       self.setLayout(layout)

    def pushbutton_run_clicked(self):

        fig, ax = setup_plot()                        
        dataq(fig, ax)

def setup_plot():

    fig, ax = plt.subplots()
    fig.canvas.manager.show()

    return fig, ax

def dataq(fig, ax):
    for i in range(200):
        ax.plot(np.random.rand(1), np.random.rand(1), 'o')
        fig.canvas.draw()
        fig.canvas.flush_events()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)    
    mywindow = MyWindowClass()
    mywindow.show()      
    sys.exit(app.exec_())

更新 - 第二个例子:

这是另一种设置艺术家的方法,可以让您更轻松地在多个函数中使用它们,并使它们的操作更加方便。

from PyQt4 import QtGui
import sys
import numpy as np

import matplotlib as mpl
mpl.use('Qt4Agg')
import matplotlib.pyplot as plt

class MyWindowClass(QtGui.QWidget):
    def __init__(self, parent=None):
       super(MyWindowClass, self).__init__(parent)

       #---- generate some data ----

       self.x = np.random.rand(50)
       self.y = np.random.rand(50)

       #---- create a layout ----

       pushButton_Run = QtGui.QPushButton('Run')
       pushButton_Run.clicked.connect(self.pushbutton_run_clicked)

       pushButton_Clear = QtGui.QPushButton('Clear')
       pushButton_Clear.clicked.connect(self.clear_plot)

       layout = QtGui.QGridLayout()
       layout.addWidget(pushButton_Run, 0, 0)
       layout.addWidget(pushButton_Clear, 1, 0)
       self.setLayout(layout)

       #---- init artists ----

       self.fig, self.ax = plt.subplots()
       self.fig.canvas.manager.show()

    def clear_plot(self):
        self.ax.cla()
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()

    def pushbutton_run_clicked(self):
        self.setEnabled(False)
        self.ax.cla()   
        dataq(self.fig, self.ax, self.x, self.y)
        dataq2(self.fig, self.ax, self.x, self.y)
        self.setEnabled(True)

def dataq(fig, ax, x, y):            
    for i in range(len(x)):
        ax.plot(x[i], y[i], 'o')
        fig.canvas.draw()
        fig.canvas.flush_events()

def dataq2(fig, ax, x, y):
    for i in range(len(x)-1):
        ax.plot(x[i:i+2], y[i:i+2], '-')
        fig.canvas.draw()
        fig.canvas.flush_events()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)    
    mywindow = MyWindowClass()
    mywindow.show()      
    sys.exit(app.exec_())