PyQt5: RuntimeError: wrapped C/C++ object of type FigureCanvasQTAgg has been deleted

Viewed 3666

So I have been looking at stackoverflow posts for the last couple of days to solve this problem that I am having, and having tried several things, I still can't manage to get my code working. I'm trying to create a simple Gui where I can show a plot when a button is pushed. When I run my main module, the program starts. But when I click my 'plot' button I get the error

RuntimeError: wrapped C/C++ object of type FigureCanvasQTAgg has been deleted

Now I read that this has something to do with a C++ object being deleted, while the python wrapper still exists, but I can't seem to solve this problem. My main concern is to keep the GUI as modular as possible, since I want to expand the sample code shown below. Does anybody has a good solution to my problem?

main.py

import sys
from PyQt5.QtWidgets import *

from GUI import ui_main

app = QApplication(sys.argv)
ui = ui_main.Ui_MainWindow()
ui.show()
sys.exit(app.exec_())

ui_main.py

from PyQt5.QtWidgets import *

from GUI import frame as fr

class Ui_MainWindow(QMainWindow):

    def __init__(self):
        super(Ui_MainWindow, self).__init__()

        self.central_widget = Ui_CentralWidget()
        self.setCentralWidget(self.central_widget)

        self.initUI()

    def initUI(self):

        self.setGeometry(400,300,1280,600)
        self.setWindowTitle('Test GUI')

class Ui_CentralWidget(QWidget):

    def __init__(self):
        super(Ui_CentralWidget, self).__init__()

        self.gridLayout = QGridLayout(self)

        '''Plot button'''
        self.plotButton = QPushButton('Plot')
        self.plotButton.setToolTip('Click to create a plot')
        self.gridLayout.addWidget(self.plotButton, 1, 0)

        '''plotFrame'''
        self.plotFrame = fr.PlotFrame()
        self.gridLayout.addWidget(self.plotFrame,0,0)

        '''Connect button'''
        self.plotButton.clicked.connect(fr.example_figure)

frame.py

from PyQt5.QtWidgets import *

from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt

class PlotFrame(QFrame):

    def __init__(self):
        super(PlotFrame, self).__init__()

        self.gridLayout = QGridLayout(self)

        self.setFrameShape(QFrame.Box)
        self.setFrameShadow(QFrame.Raised)
        self.setLineWidth(3)

        self.figure = plt.figure(figsize=(5, 5))
        self.canvas = FigureCanvas(self.figure)
        self.gridLayout.addWidget(self.canvas,1,1)

def example_figure():

    plt.cla()
    ax = PlotFrame().figure.add_subplot(111)
    x = [i for i in range(100)]
    y = [i ** 0.5 for i in x]
    ax.plot(x, y, 'r.-')
    ax.set_title('Square root plot')
    PlotFrame().canvas.draw()
1 Answers

Every time you use PlotFrame() a new object is created, and in your case you are creating 2 objects in example_figure but they are local so they will be automatically deleted when that function is executed causing the error you point out since the reference is lost When removing the object without notifying matplotlib, a solution is to pass the object to the function.

ui_main.py

# ...

class Ui_CentralWidget(QWidget):
    # ...
        '''Connect button'''
        self.plotButton.clicked.connect(self.on_clicked)

    def on_clicked(self):
        fr.example_figure(self.plotFrame)

frame.py

# ...

def example_figure(plot_frame):
    plt.cla()
    ax = plot_frame.figure.add_subplot(111)
    x = [i for i in range(100)]
    y = [i ** 0.5 for i in x]
    ax.plot(x, y, 'r.-')
    ax.set_title('Square root plot')
    plot_frame.canvas.draw()
Related