schlenzmeister
schlenzmeister

Reputation: 149

Passing matplotlib plot/axes for PyQt5 embedded plots

I had a question yesterday about how to update an embedded matplotlib plot in a pyqt5 gui with toolbar which works fine now. But in my application it is more complex compared to the minimal example.

I have a class that is doing the analysis and creating plots via matplotlib while the GUI is in a separated class in another file. I made a modified minimal example:

# -*- coding: utf-8 -*-

import sys
import numpy as np

from PyQt5 import QtCore, QtWidgets, uic

import matplotlib
matplotlib.use('QT5Agg')

import matplotlib.pylab as plt

from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
from matplotlib.backends.backend_qt5agg import FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure

class Analysis():

    def __init__(self):

        self.fig, self.ax1 = plt.subplots()

        bins = np.arange(0.1, 2, 0.02)
        data = np.random.rand(3,2)        
        self.ax1.hist(data, bins, alpha=0.6, density=False, cumulative=False)      

    def getAxis(self):
        return self.ax1


class MyWindow(QtWidgets.QMainWindow):

    def __init__(self):

        super(MyWindow, self).__init__()
        uic.loadUi('test.ui', self) 

        # default data
        data = np.array([0.7,0.7,0.7,0.8,0.9,0.9,1.5,1.5,1.5,1.5])        
        self.fig, self.ax1 = plt.subplots()

        bins = np.arange(0.1, 2, 0.02)
        n1, bins1, patches1 = self.ax1.hist(data, bins, alpha=0.6, density=False, cumulative=False)

        # plot
        self.plotWidget = FigureCanvas(self.fig)
        self.lay = QtWidgets.QVBoxLayout(self.content_plot)  
        self.lay.setContentsMargins(0, 0, 0, 0)      
        self.lay.addWidget(self.plotWidget)

        # add toolbar
        self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(self.plotWidget, self))        

        # button event
        self.pushButton.clicked.connect(self.update)

        # show window
        self.show() 

    #############################################     

    def update(self):

        # clear local axis
        self.ax1.cla()   

        # get axis from analysis object
        a = Analysis()        
        ax = a.getAxis()

        # ???????????
        self.ax1 = ax

        # draw the new content
        self.fig.canvas.draw_idle()  



if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = MyWindow()
    sys.exit(app.exec_())

The idea is to create a matplotlib object in the Analysis class and to store the axes of the results to get them in another method to plot it on an embedded PyQt5 widget.

But my code doesn't work. It cleans the local axes but it doesn't set the axes from the Analysis object. How can I do that correctly?

Thanks!

Upvotes: 1

Views: 554

Answers (1)

Diziet Asahi
Diziet Asahi

Reputation: 40667

You are creating a new figure and axes in your class Analysis. You cannot take one axes from one figure and put it in another figure just like that. Instead, design your Analysis class so it takes an Axes object at initialization.

You may want to read matplotlib's coding style document.

class Analysis():
    def __init__(self, ax=None):
        if ax is None:
            ax = plt.gca()

        bins = np.arange(0.1, 2, 0.02)
        data = np.random.rand(3,2)        
        ax.hist(data, bins, alpha=0.6, density=False, cumulative=False)

(...)

    def update(self):

        # clear local axis
        self.ax1.cla()   
        a = Analysis(ax=self.ax1)        
        self.fig.canvas.draw_idle()

Upvotes: 3

Related Questions