Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotting matplotlib figure inside QWidget using Qt Designer form and PyQt5

Tags:

I don't understand the best way to link a matplotlib figure to a form created from Qt Designer. I have a form I created in QtDesigner and then compiled to python through pyuic5. My main program is:

import app_framework as af import matplotlib from PyQt5 import QtWidgets import sys  matplotlib.use('Qt5Agg')  app = QtWidgets.QApplication(sys.argv) form = af.MyApp() form.show() app.exec_() 

where myApp calls the app_framework.py form created from Qt Designer then converted by pyuic5 (design.py):

from PyQt5.QtWidgets import QApplication, QMainWindow import design  class MyApp(QMainWindow, design.Ui_mainWindow):    def __init(self):        super(self.__class__, self).__init__()        <button initializations>        <function definitions for button callbacks> 

I'm confused as to where in this framework I can link a matplotlib figure to a premade empty widget in QtDesigner, or something of that sort, so that I can plot new data in the GUI window as things happen (text entered, button push, etc.)

I've found some threads here on SO and matplotlib's site, but I'm not sure I understand the correct process for creating the space for this widget in the Qt Designer form then linking a plot, and/or creating a widget post hoc and then linking and plotting.

What I've done so far is create an empty QWidget inside Qt Creator and then after pyuic5 compile, I alter the design.py file as follows:

from PyQt5 import QtCore, QtGui, QtWidgets  # **** ADDED THIS from matplotlib.figure import Figure from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas # ****   class Ui_mainWindow(object):     def setupUi(self, mainWindow):         <mainWindow setup stuff>         self.centralwidget = QtWidgets.QWidget(mainWindow)          # ****ALTERED THIS FROM self.plotWidget = QtWidgets.QWidget(self.centralWidget)         self.plotWidget = MplWidget(self.centralWidget)         # *****           self.plotWidget.setGeometry(QtCore.QRect(20, 250, 821, 591))         self.plotWidget.setObjectName("plotWidget")    # **** ADDED THIS  class MplCanvas(Canvas):     def __init__(self):         self.fig = Figure()         self.ax = self.fig.add_subplot(111)         Canvas.__init__(self, self.fig)         Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)         Canvas.updateGeometry(self)   class MplWidget(QtWidgets.QWidget):     def __init__(self, parent=None):         QtWidgets.QWidget.__init__(self, parent)         self.canvas = MplCanvas()  # *********** 

and then app_framework.py as:

from PyQt5.QtWidgets import QApplication, QMainWindow import design  class MyApp(QMainWindow, design.Ui_mainWindow):    def __init(self):        super(self.__class__, self).__init__()        self.setupUi(self)        self.pushButton_plotData.clicked.connect(self.plot_data)      def plot_data(self):         x=range(0, 10)         y=range(0, 20, 2)         self.plotWidget.canvas.ax.plot(x, y)         self.plotWidget.canvas.draw() 

I thought this would work, but when I click the plot push button, nothing happens. It doesn't lock up, it just doesn't plot anything. I'm guessing I'm missing something fundamental for plotting a matplotlib figure and/or canvas in this empty widget.

like image 833
launchpadmcquack Avatar asked May 12 '17 22:05

launchpadmcquack


People also ask

Can you use Qt Designer with Pyside?

PySide2 Tutorial — Creating applications with Qt Designer The good news is that Qt comes with a graphical editor — Qt Designer — which contains a drag-and-drop UI editor. Using Qt Designer you can define your UIs visually and then simply hook up the application logic later.

Is Pyqtgraph faster than Matplotlib?

matplotlib: For plotting, pyqtgraph is not nearly as complete/mature as matplotlib, but runs much faster. Matplotlib is more aimed toward making publication-quality graphics, whereas pyqtgraph is intended for use in data acquisition and analysis applications.

Why is %Matplotlib inline?

The line magic command %matplotlib inline enables the drawing of matplotlib figures in the IPython environment. Once this command is executed in any cell, then for the rest of the session, the matplotlib plots will appear directly below the cell in which the plot function was called.


1 Answers

I found the solution through the help of this SO post, which links to this free sample chapter of a book I'm probably gonna need to buy. As sort of mentioned in a number of other posts, one needs to "Promote" the blank QtWidget to a MplWidget using the header mplwidget. After doing this, and then running the pyuic5 command, "from mplwidget import MplWidget" will appear in the design.py file which can be updated anytime without worry about overwritting. Then, create an mplwidget.py file with:

# Imports from PyQt5 import QtWidgets from matplotlib.figure import Figure from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas import matplotlib  # Ensure using PyQt5 backend matplotlib.use('QT5Agg')  # Matplotlib canvas class to create figure class MplCanvas(Canvas):     def __init__(self):         self.fig = Figure()         self.ax = self.fig.add_subplot(111)         Canvas.__init__(self, self.fig)         Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)         Canvas.updateGeometry(self)  # Matplotlib widget class MplWidget(QtWidgets.QWidget):     def __init__(self, parent=None):         QtWidgets.QWidget.__init__(self, parent)   # Inherit from QWidget         self.canvas = MplCanvas()                  # Create canvas object         self.vbl = QtWidgets.QVBoxLayout()         # Set box for plotting         self.vbl.addWidget(self.canvas)         self.setLayout(self.vbl) 

Then, the app framework can be as I had earlier. When run, and pushing the plot button, the figure appears as expected. I think I basically had done everything to "Promote" the QWidget by hand just missing the vbl stuff, but all that would be overwritten everytime the Qt Designer form is editted.

app_framework.py:

from PyQt5.QtWidgets import QApplication, QMainWindow import design  class MyApp(QMainWindow, design.Ui_mainWindow):    def __init(self):        super(self.__class__, self).__init__()        self.setupUi(self)        self.pushButton_plotData.clicked.connect(self.plot_data)      def plot_data(self):         x=range(0, 10)         y=range(0, 20, 2)         self.plotWidget.canvas.ax.plot(x, y)         self.plotWidget.canvas.draw() 

main.py:

from PyQt5 import QtWidgets import sys  # Local Module Imports import app_framework as af  # Create GUI application app = QtWidgets.QApplication(sys.argv) form = af.MyApp() form.show() app.exec_() 
like image 158
launchpadmcquack Avatar answered Sep 20 '22 14:09

launchpadmcquack