matplotlib with PyQt GUIs

January 20th, 2009 at 10:00 pm

A few months ago I posted a couple of demo snippets for embedding matplotlib plots into wxPython GUIs.

Well, as I’m now in the process of moving to PyQt for my GUI needs in Python, I’ve reimplemented one of the demos with PyQt. Here’s a screenshot:

PyQt with matplotlib

And the demo itself can be taken from here.

The demo features:

  • Using the maplotlib navigation toolbar
  • Adding data to the plot dynamically
  • Dynamically modifying the plot’s properties
  • Processing matplotlib events in the GUI
  • Saving the plot to a file from a menu

The embedding of matplotlib into PyQt is relatively smooth and similar to wxPython, with a couple of tiny differences (which mainly have to do with how the two frameworks handle parenting of GUI elements). Note that I’ve reimplemented only one of the demos, but it’s really sufficient for getting started with combining the two libraries.

Related posts:

  1. matplotlib with wxPython GUIs
  2. matplotlib – plotting with Python
  3. More PyQt plotting demos
  4. Plotting in Python: matplotlib vs. PyQwt
  5. Book review: “Matplotlib for Python developers” by Sandro Tosi

31 Responses to “matplotlib with PyQt GUIs”

  1. xavierNo Gravatar Says:

    That’s cool :)

    However, I’m missing on key feature for my application:
    I need to plot a image with a pyqt application. That is no pb AFAICS.
    The problem is that I need to be able to click on the image to get the corresponding pixel value ((X,Y) and the value).
    A display “x=, y=” within the matplotlib backend is not sufficient.
    I need to be able to use these values into my pyqt code.
    For instance, each time I click on the image, I show the pixel value within a qlineedit.

    Is it even possible? If not, I’m in trouble with pylab+pyqt.

  2. elibenNo Gravatar Says:

    For that I doubt you need matplotlib. Qt has excellent support for showing images, for example with something like QGraphicsView. I’m not sure this is exactly the class you need, but it’s probably not very far from the truth.

  3. xavierNo Gravatar Says:

    It is true that QGraphicsView could do the job when I only want to plot an image.

    However, I do need matplotlib because I need all the plotting capabilities of matplotlib (latex, alpha, shapes overplot). OK ok I can do that within the
    QGraphicsView framework but I would prefer not to redevelop part of matplotlib in qt4 ;)

    The only thing I’m missing is a link to get the (x,y,pixel) values under the mouse into my python code.

    If it is not possible at all, then I’m going to use QGraphicsView to display images and matplotlib to display functions and scatter plot. I would be the backup solution…but I would lose the nice and easier_to_use subplot capabilities of matplotlib (mixing images and scatter plot for instance).

    Do you see a chance to get this link?

  4. xavierNo Gravatar Says:

    Wait wait wait…I’m a dumbass.
    I haven’t seen matplotlib.backend_bases.PickEvent … I’m pretty sure that is what I need…

  5. xavierNo Gravatar Says:

    Unfortunately, there is a bug :( :
    If you zoom on the image using the standard zoom button of the matplotlib toolbar, then the axes go back to there “nominal” state each time the on_draw even is called (e.g. each time you cover/uncover the window).

    I’m not sure how it should be fixed…the on_draw even should only redraw a precomputed image…but I have no idea how the code should looks like so far.

  6. SamNo Gravatar Says:

    I enjoyed your example but I had to make a small change for the matplotlib API’s that are present on Kubuntu 8.04:

    #box_points = event.artist.get_bbox().get_points()
    box_points = event.artist.get_verts()
    msg = “You’ve clicked on a bar with coords:\n %s” % str(box_points)

    My API for matplotlib.patches.Rectangle has no get_bbox().
    cheers!

  7. PraneethNo Gravatar Says:

    Cool – Just the example I was looking for :)

  8. PradheepNo Gravatar Says:

    Thank you very much for the matplotlib-pyqt interface code. Very helpful :-)

  9. TonduNo Gravatar Says:

    You example doesn’t seem to run with matplotlib 0.99.1.1 and pyqt 4.6 and leads to a segmentation fault. The problem seems to come from the NavigationToolBar (if I comment the 2 lines concerning the NavigationToolBar it’s OK). I guess, this problem comes from the qt4agg backend of matplotlib which has not been updated to the new pyqt4.6 version.

  10. IanNo Gravatar Says:

    Is it possible to extend the mouse interaction to the axis labels, for instance to pop up some resource browser to edit range, number of decimal points, etc. The current mouse picks seem to only work on the actual bars in the plot area. Any hints please?

  11. elibenNo Gravatar Says:

    @Ian, it could be possible by exploring the event types mpl_connect accepts. Here‘s a sample documentation link on the subject.

  12. PaulNo Gravatar Says:

    Tondu – I find that:

    from matplotlib.backends.backend_qt4 import NavigationToolbar2QT as NavigationToolbar

    will give you the toolbar back.

    … and thanks to Eli for this outline of how to embed matplotlib into pyqt.
    –Paul

  13. kingair_sixNo Gravatar Says:

    thanks so much, very helpful for integrating matplotlib, would have taken ages without an appropriate demo.

  14. Nils WagnerNo Gravatar Says:

    How can I print the plot using QPrinter ?

  15. elibenNo Gravatar Says:

    Nils,

    Unfortunately I have absolutely no experience working with QPrinter and printing in Qt in general. Hopefully someone else will be able to help you. IIRC matplotlib has capabilities to export its plots to images and other format – maybe this can be the path.

  16. Nils WagnerNo Gravatar Says:

    Eli,

    matplotlib provides http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.savefig
    How do I proceed if I have stored the plot ?

  17. elibenNo Gravatar Says:

    Nils,

    Well, then I guess you can load the image and paint it onto QPrinter since it’s a QPaintDevice. Searching through the examples that come with PyQt there are a lot of hits on QPrinter, so you may find some useful stuff there.

  18. MihaiNo Gravatar Says:

    Very useful example.
    Thank you very much for your effort

  19. WladimirNo Gravatar Says:

    Thanks! This is incredibly useful.

  20. TylerNo Gravatar Says:

    Hello,

    First of all, amazing tutorial! However, I am trying to get the figure to dynamically resize to fit its QWidget container.

    Any suggestions??

    Tyler

  21. Nils WagnerNo Gravatar Says:

    I added a printer button to the navigation toolbar in matplotlib.
    However the quality of the print-out is poor using QPrinter.
    Moreover the frame including the navigation toolbar is printed.
    How can I omit that ?

    How can I improve the quality of the hardcopy ? If I save the figure before, the print-out of the image is o.k.
    Can anybody offer any solutions to this ?
    import sys
    import numpy as np
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    #from xlwt import *
    from pylab import plot, show

    from matplotlib.figure import Figure
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar2

    class ViewWidget(QMainWindow):
    def __init__(self):
    QMainWindow.__init__(self)

    # create a simple main widget to keep the figure
    self.mainWidget = QWidget()
    self.setCentralWidget(self.mainWidget)

    layout = QVBoxLayout()
    self.mainWidget.setLayout(layout)

    # create a figure
    self.figure_canvas = FigureCanvas(Figure())
    layout.addWidget(self.figure_canvas, 10)

    # and the axes for the figure
    self.axes = self.figure_canvas.figure.add_subplot(111)
    x = np.linspace(0.,2*np.pi,100)
    self.axes.plot(x,np.sin(x),label='sin(x) ')
    self.axes.plot(x,np.cos(x),label='cos(x) ')
    self.axes.figure.set_facecolor('white')
    self.axes.grid('on')
    self.axes.legend()
    # add a navigation toolbar
    self.navigation_toolbar = NavigationToolbar2(self.figure_canvas, self)
    layout.addWidget(self.navigation_toolbar, 0)

    self.print_button = QPushButton()
    self.print_button.setIcon(QIcon("Fileprint.png"))
    self.print_button.setToolTip("Print the figure")
    self.navigation_toolbar.addWidget(self.print_button)
    self.connect(self.print_button, SIGNAL('clicked()'), self.goPrinter)

    self.quit_button = QPushButton("&Quit")
    self.navigation_toolbar.addWidget(self.quit_button)
    self.connect(self.quit_button, SIGNAL('clicked()'), self.close)

    def goPrinter(self):
    printer = QPrinter()
    anotherWidget= QPrintDialog(printer,self)
    if(anotherWidget.exec_() != QDialog.Accepted):
    return
    p = QPixmap.grabWidget(self)
    printLabel = QLabel()
    printLabel.setPixmap(p)
    painter = QPainter(printer)
    printLabel.render(painter)
    painter.end()

    show()

    if __name__=="__main__":
    app=QApplication(sys.argv)
    mw=ViewWidget()
    mw.show()
    sys.exit(app.exec_())

  22. Nils WagnerNo Gravatar Says:

    Eli,

    here comes the corrected version
    http://pastebin.com/vR0X5DQc

  23. Nils WagnerNo Gravatar Says:

    I tried to combine an event with annotation.
    However, the annotation is not visible, when I click on the curves.
    How can I resolve the problem ?
    The code is available at http://pastebin.com/QxKBZtaX
    Any pointer would be appreciated.

  24. elibenNo Gravatar Says:

    Nils,

    I no longer support this code. Sorry. I suggest you take specific questions elsewhere like StackOverflow or the PyQt/matplotlib forums/mailing lists.

  25. SourabhNo Gravatar Says:

    Hi

    I get a segmentation fault when I try to save the file. Can you guide me on what the problem could be.

  26. Jules JacobsNo Gravatar Says:

    Thank you so much! This saved me so much time of figuring out the right API calls to make :)

  27. Virgil StokesNo Gravatar Says:

    Great work Eli and thanks for making it available to the Python community :-)
    One simple question --- which would you choose for building a GUI, wxPython or PyQt?
    Any comments positive or negative on wxPython and PyQt would be greatly appreciated.

  28. elibenNo Gravatar Says:

    @Virgil,

    I suggest you do a search on my site for PyQt – I’ve written a bit about the reasons for switching to it from wxPython a long while ago.

  29. RossNo Gravatar Says:

    I’ve got a weird case. The GUI app is basically a form where I fill in parameters. Signal uses .plot() to print a chart in a new pop-up window. Works flawlessly when I run from a python interpreter. But when I launch the GUI app from clicking on it’s desktop icon (like a windows user is prone to do), the GUI is visible, but the expected .plot window never materializes. Not even sure how to debug it since it works without issue from the Spyder built-in interpreter. Any ideas?

  30. MikeNo Gravatar Says:

    Running produces the following errors — is this a PyQt version issue? Any ideas?

    TypeError: ‘PySide.QtGui.QWidget.setParent’ called with wrong argument types:
    PySide.QtGui.QWidget.setParent(QWidget)
    Supported signatures:
    PySide.QtGui.QWidget.setParent(PySide.QtGui.QWidget)
    PySide.QtGui.QWidget.setParent(PySide.QtGui.QWidget, PySide.QtCore.Qt.WindowFlags)

  31. MikeNo Gravatar Says:

    Solved my own problem above. Found solution on stack overflow:

    http://stackoverflow.com/questions/18620087/running-matplotlib-with-pyqt-on-windows