Search code examples
pythonmatplotlibpyqtqtgui

How to display a value in a PyQt text field using matplotlib's object picking function?


I am using PyQt 4 for a basic GUI and matplotlib for a plot from which I want to read the coordinates of the plotted data points. Based on these examples (simple picking example), I have the simple problem that I cannot display the coordinates of a data point in a text field such as QtGui.QLabel(). I do not understand why I cannot call the instance Window.msg in the method onpick(). Probably it is because the instance it not given to the method. I only have a basic understanding of object oriented programming (but I am working on it), so the problem is my lack of knowledge.

My question: How to display the coordinates of chosen data (by clicking on it) from a matplotlib plot in my GUI based on PyQT (in that case in my label lbl)?

Also, it would be nice to highlight the chosen data point in the plot.

Here is my code (working):

import numpy as np
import matplotlib.pyplot as plt
from PyQt4 import QtGui
import sys
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
import matplotlib.pyplot as plt


class Window(QtGui.QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.initUI()

    def initUI(self):  
       self.msg = '0'

       # a figure instance to plot on
       self.figure = plt.figure()
       self.canvas = FigureCanvas(self.figure)
       self.toolbar = NavigationToolbar(self.canvas, self)

       # a label
       self.lbl = QtGui.QLabel(self.msg)

       # set the layout
       layout = QtGui.QVBoxLayout()
       layout.addWidget(self.toolbar)
       layout.addWidget(self.canvas)
       layout.addWidget(self.lbl)
       self.setLayout(layout)

       self.plot()

    def plot(self):
        # random data
        data = [np.random.random() for i in range(10)]
        # create an axis
        ax = self.figure.add_subplot(111)
        # discards the old graph
        ax.hold(False)
        # plot data
        line, = ax.plot(data, 'o', picker=5)  # 5 points tolerance
        self.canvas.draw()
        self.canvas.mpl_connect('pick_event',  Window.onpick)

    def onpick(self):
        thisline = self.artist
        xdata = thisline.get_xdata()
        ydata = thisline.get_ydata()
        ind = self.ind

        # show data
        self.msg = (xdata[ind], ydata[ind])
        print(self.msg)

        # This does not work:
        #Window.lbl.setText(self.msg)


if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    main = Window()
    main.show()
    sys.exit(app.exec_())

Solution

  • The self is being overlapped by the picker (not sure why). In any case this should work:

    import numpy as np
    import matplotlib.pyplot as plt
    from PyQt4 import QtGui
    import sys
    from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
    import matplotlib.pyplot as plt
    
    class Window(QtGui.QDialog):
        def __init__(self, parent=None):
            super(Window, self).__init__(parent)
            self.initUI()
    
        def initUI(self):  
           self.msg = '0'
    
           # a figure instance to plot on
           self.figure = plt.figure()
           self.canvas = FigureCanvas(self.figure)
           self.toolbar = NavigationToolbar(self.canvas, self)
    
           # a label
           self.lbl = QtGui.QLabel(self.msg)
    
           # set the layout
           layout = QtGui.QVBoxLayout()
           layout.addWidget(self.toolbar)
           layout.addWidget(self.canvas)
           layout.addWidget(self.lbl)
           self.setLayout(layout)
    
           self.plot()
    
        def changelabel(arg):
            main.lbl.setText(str(arg[0])+' '+str(arg[1]))
    
        def plot(self):
            # random data
            data = [np.random.random() for i in range(10)]
            # create an axis
            ax = self.figure.add_subplot(111)
            # discards the old graph
            ax.hold(False)
            # plot data
            line, = ax.plot(data, 'o', picker=5)  # 5 points tolerance
            self.canvas.draw()
            self.canvas.mpl_connect('pick_event',  Window.onpick)
    
        def onpick(self):
            thisline = self.artist
            xdata = thisline.get_xdata()
            ydata = thisline.get_ydata()
            ind = self.ind
    
            # show data
            self.msg = (xdata[ind], ydata[ind])
            print(self.msg)
    #        Window.changelabel(self.msg)
            main.lbl.setText(str(self.msg[0])+' '+str(self.msg[1]))
    
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        main = Window()
        main.show()
        sys.exit(app.exec_())
    

    , the change is in the setText function, since I call it directly from the variable (no self or Window).

    main.lbl.setText(str(self.msg[0])+' '+str(self.msg[1]))