【发布时间】:2020-10-27 19:48:47
【问题描述】:
我使用 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 会显示两个图。
基于对类似问题的回答(例如matplotlib.pyplot will not forget previous plots - how can I flush/refresh?),我尝试了各种方法,例如关注plt.show() 和plt.cla() plt.clf() 和plt.close(),但它们都没有解决问题。正如您在我的代码中看到的那样,我已将 plt.close() 添加到 PyQt5 窗口关闭事件以及常规 MPL 图中,但这似乎无济于事。
编辑:既然问题已经得到解答,我已经清理了一些随后的思考并将其简化为相关信息。
我在我的工作 Linux 机器(最初在 Mac 上开发)上尝试了这段代码,但没有得到相同的双标行为。这表明它依赖于平台。
在 Linux 上,我实际上可以从 plot2 方法中删除 plt.close(),我可以从 PlotWindow 类中删除 closeEvent 方法,它可以正常工作而不会显示任何双图。
【问题讨论】:
-
几个可能的错误......如果您的代码是直接复制的,那么可能没有帮助。但是在使用 guis 时,最小的事情有时会导致大问题......无论如何。在 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.figure(1) ?可能两个调用实际上都指的是同一个图形窗口(即使您试图避免这种情况)。在其中添加“1”将(希望)强制它使用不同的数字
-
刚试了一下 Andrew 没区别 :-(
标签: matplotlib pyqt5