我怎样才能阻止封闭的Matplotlib阴谋再次困扰我?

我怎样才能阻止封闭的Matplotlib阴谋再次困扰我?,matplotlib,pyqt5,Matplotlib,Pyqt5,我已经编写了一个使用PyQt5和Matplotlib的大型数据处理和绘图应用程序,在创建新的绘图时,旧的绘图会重新出现,这让我很苦恼。关于这一点,我已经看到了很多问题的答案,但没有一个建议的方法适合我 我已将问题归结为以下简化代码: from PyQt5.QtWidgets import (QApplication, QMainWindow, QDialog, QPushButton, QVBoxLayout, QGroupBox) from matplotlib.backends.ba

我已经编写了一个使用PyQt5和Matplotlib的大型数据处理和绘图应用程序,在创建新的绘图时,旧的绘图会重新出现,这让我很苦恼。关于这一点,我已经看到了很多问题的答案,但没有一个建议的方法适合我

我已将问题归结为以下简化代码:

from PyQt5.QtWidgets import (QApplication, QMainWindow, QDialog, QPushButton,
    QVBoxLayout, QGroupBox)
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import sys

class PlotCanvas(FigureCanvas):
    """ Subclass of the MPL FigureCanvas class. """
    def __init__(self, parent=None):
        self.parent = parent
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.fig.set_tight_layout(True)
        FigureCanvas.__init__(self, self.fig)

class PlotWindow(QDialog):
    """ Create plot in window and plot supplied data. """
    def __init__(self, parent, x, y):
        super().__init__()
        self.parent = parent
        self.x = x
        self.y = y
        self.set_up_gui()
        self.l2d = self.canvas.ax.plot(self.x, self.y)[0]

    def set_up_gui(self):
        """ Create GUI. """
        vbl = QVBoxLayout()
        self.canvas = PlotCanvas(self)
        vbl.addWidget(self.canvas)
        self.setLayout(vbl)

    def closeEvent(self, event):
        """ Delete figure on closing window. """
        plt.close(self.canvas.fig)
        super(PlotWindow, self).closeEvent(event)

class MainApp(QMainWindow):
    """ My main application class """
    def __init__(self, parent=None):
        super(QMainWindow, self).__init__()
        # Create some arbitrary data
        self.x = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        self.y = [2, 4, 6, 4, 2, 4, 6, 8, 6]
        self.set_up_gui()

    def set_up_gui(self):
        """ Create GUI with 2 buttons for creating 2 plots. """
        btn1 = QPushButton()
        btn1.setText('Button 1')
        btn1.clicked.connect(self.plot1)
        btn2 = QPushButton()
        btn2.setText('Button 2')
        btn2.clicked.connect(self.plot2)
        vbl = QVBoxLayout()
        vbl.addWidget(btn1)
        vbl.addWidget(btn2)
        gb = QGroupBox()
        gb.setLayout(vbl)
        self.setCentralWidget(gb)

    def plot1(self):
        """ Plot using my PlotWindow class. """
        p = PlotWindow(self, self.x, self.y)
        p.show()

    def plot2(self):
        """ Plot using regular MPL plot call. """
        fig = plt.figure()
        plt.plot([10, 20, 30], [4, 8, 2])
        plt.show()
        plt.close(fig)

if __name__=='__main__':
    app = QApplication(sys.argv)
    main = MainApp()
    main.show()
    sys.exit(app.exec_())
奇怪的行为是:

  • 按按钮1,出现绘图1,按红色X关闭窗口
  • 按按钮2,出现绘图2,按红色X关闭窗口
  • 按按钮1,出现绘图1,按红色X关闭窗口
  • 按下按钮2,绘图2出现,绘图1也出现,按下红色X关闭绘图2,绘图1也关闭
  • 从这里开始,按钮1显示绘图1,按钮2显示两个绘图
基于对类似问题(例如)的回答,我尝试了各种方法,例如使用
plt.cla()
plt.clf()
plt.close()
执行以下操作,但没有一种方法可以解决问题。正如您在我的代码中所看到的,我已将
plt.close()
添加到PyQt5窗口关闭事件以及常规MPL绘图中,但这似乎没有任何作用

编辑:现在问题已经回答了,我已经整理了一些接下来的思考,并将其简化为相关信息

我在我的工作Linux机器(最初在Mac上开发)上尝试了这段代码,但没有得到相同的双重打印行为。这表明它依赖于平台


在Linux上,我可以从plot2方法中删除
plt.close()
,也可以从
PlotWindow
类中删除
closeEvent
方法,它工作正常,没有任何双图显示。

好的,通过试用结束错误,我已经修复了这个问题。我并不声称确切知道它是如何被修复的。也许看到我是如何修复它的,一些聪明的人可以解释为什么它会修复它

如果我将
PlotCanvas
中的
closeEvent
方法更改为以下内容(我已将添加的行标记为星号):

并将
plot2
方法更改为以下内容:

    def plot2(self):
        """ Plot using regular MPL call. """
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.plot([10, 20, 30], [4, 8, 2])
        plt.show()
        ax.cla() # ****
        fig.clf() # ****
        plt.close(fig)

我现在没有看到多个绘图。我本以为
在关闭时会与
容器一起关闭,但显然不是。我也希望我能独立于平台获得相同的行为,但MacOSX后端的行为似乎与其他后端有所不同。

一些可能的错误。。。idk,如果您的代码是直接复制的,那么可能没有帮助。但是当使用GUI时,最小的东西有时会导致大问题。。。无论如何在plot1下,创建一个PlotWindow并传入self.x两次,但它需要x和y。此外,在plot2中,使用plt.figure(),但在PlotCanvas中,使用matplotlib.figure.figure()。我不知道为什么要使用两种不同的实现说实话,把它剥离成一些有效的东西有点困难,我不得不稍微改变一些小事情,比如处理什么数据。修正了self.x重复,正如你正确预期的,应该是x,y。至于使用不同的实现,plt.figure()是我的快速绘图方式,因此我可以在不创建新绘图窗口的情况下快速绘制顶级绘图。我很确定我已经从一些在线示例中获得了matplotlib.figure.figure()的用法。现在已经尝试了这两种实现,但问题仍然存在。这可能是愚蠢的,但您是否尝试过在plot2创建中使用fig=plt。图(1)?这可能是因为两个调用实际上都指向同一个图形窗口(尽管您试图避免这样做)。在其中添加“1”(希望)将强制它使用不同的图形只是尝试了Andrew,没有任何区别:-(
    def plot2(self):
        """ Plot using regular MPL call. """
        fig = plt.figure()
        ax = fig.add_subplot(111)
        ax.plot([10, 20, 30], [4, 8, 2])
        plt.show()
        ax.cla() # ****
        fig.clf() # ****
        plt.close(fig)