How to embed matplotlib in pyqt - for Dummies
It is not that complicated actually. Relevant Qt widgets are in matplotlib.backends.backend_qt4agg
. FigureCanvasQTAgg
and NavigationToolbar2QT
are usually what you need. These are regular Qt widgets. You treat them as any other widget. Below is a very simple example with a Figure
, Navigation
and a single button that draws some random data. I've added comments to explain things.
import sysfrom PyQt4 import QtGuifrom matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvasfrom matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbarfrom matplotlib.figure import Figureimport randomclass Window(QtGui.QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) # a figure instance to plot on self.figure = Figure() # this is the Canvas Widget that displays the `figure` # it takes the `figure` instance as a parameter to __init__ self.canvas = FigureCanvas(self.figure) # this is the Navigation widget # it takes the Canvas widget and a parent self.toolbar = NavigationToolbar(self.canvas, self) # Just some button connected to `plot` method self.button = QtGui.QPushButton('Plot') self.button.clicked.connect(self.plot) # set the layout layout = QtGui.QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) self.setLayout(layout) def plot(self): ''' plot some random stuff ''' # random data data = [random.random() for i in range(10)] # create an axis ax = self.figure.add_subplot(111) # discards the old graph ax.clear() # plot data ax.plot(data, '*-') # refresh canvas self.canvas.draw()if __name__ == '__main__': app = QtGui.QApplication(sys.argv) main = Window() main.show() sys.exit(app.exec_())
Edit:
Updated to reflect comments and API changes.
NavigationToolbar2QTAgg
changed withNavigationToolbar2QT
- Directly import
Figure
instead ofpyplot
- Replace deprecated
ax.hold(False)
withax.clear()
Below is an adaptation of previous code for using under PyQt5 and Matplotlib 2.0.There are a number of small changes: structure of PyQt submodules, other submodule from matplotlib, deprecated method has been replaced...
import sysfrom PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayoutfrom matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvasfrom matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbarimport matplotlib.pyplot as pltimport randomclass Window(QDialog): def __init__(self, parent=None): super(Window, self).__init__(parent) # a figure instance to plot on self.figure = plt.figure() # this is the Canvas Widget that displays the `figure` # it takes the `figure` instance as a parameter to __init__ self.canvas = FigureCanvas(self.figure) # this is the Navigation widget # it takes the Canvas widget and a parent self.toolbar = NavigationToolbar(self.canvas, self) # Just some button connected to `plot` method self.button = QPushButton('Plot') self.button.clicked.connect(self.plot) # set the layout layout = QVBoxLayout() layout.addWidget(self.toolbar) layout.addWidget(self.canvas) layout.addWidget(self.button) self.setLayout(layout) def plot(self): ''' plot some random stuff ''' # random data data = [random.random() for i in range(10)] # instead of ax.hold(False) self.figure.clear() # create an axis ax = self.figure.add_subplot(111) # discards the old graph # ax.hold(False) # deprecated, see above # plot data ax.plot(data, '*-') # refresh canvas self.canvas.draw()if __name__ == '__main__': app = QApplication(sys.argv) main = Window() main.show() sys.exit(app.exec_())
For those looking for a dynamic solution to embed Matplotlib in PyQt5 (even plot data using drag and drop). In PyQt5 you need to use super on the main window class to accept the drops. The dropevent function can be used to get the filename and rest is simple:
def dropEvent(self,e): """ This function will enable the drop file directly on to the main window. The file location will be stored in the self.filename """ if e.mimeData().hasUrls: e.setDropAction(QtCore.Qt.CopyAction) e.accept() for url in e.mimeData().urls(): if op_sys == 'Darwin': fname = str(NSURL.URLWithString_(str(url.toString())).filePathURL().path()) else: fname = str(url.toLocalFile()) self.filename = fname print("GOT ADDRESS:",self.filename) self.readData() else: e.ignore() # just like above functions
For starters the reference complete code gives this output: