wallr2357
wallr2357

Reputation: 3

connecting mouse clicks to pyqt5 GUI label

I have a set of routines that essentially mirror the solution found here, except that I have my plot function in its own class that I import. I do this instead of leaving the code as a method within the MyApp class as the solution has in the given link. I make the code to plot the data in its own file because the actual code is very verbose.

My goal: I am trying to make it such that clicking on the graph will change a label in the GUI.

I've tried researching signals/slots and inheritance, but can't grasp how they can connect or apply when a module load is involved. Keep in mind I'm creating the GUI in PyQtDesigner.

Here is my code

main.py

import sys
from PyQt5.QtWidgets import QMainWindow
from PyQt5 import QtWidgets

from timeseries import plotData
import design

class MyApp(QMainWindow, design.Ui_MainWindow, plotData):
    
    def __init__(self, parent=None):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        
        self.x = [1,2,3,4,5]
        self.y = [1,2,3,4,5]
        
         # Button click plots the timeseries in the first timeseries plot widget
        self.pushButton_plotData.clicked.connect(lambda: self.plot())

if __name__ == '__main__':
    
    # Create GUI application
    app = QtWidgets.QApplication(sys.argv)
    form = MyApp()
    form.show()
    app.exec_()

mplwidget.py

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(dpi=100)
        self.ax = self.fig.add_subplot(111)
        
        Canvas.__init__(self, self.fig)
        Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, 
                             QtWidgets.QSizePolicy.Expanding)
        Canvas.updateGeometry(self)

        # Call when user clicks in the plot window
        Canvas.mpl_connect(self, s='button_press_event', func=self.get_coord)
        
    def get_coord(self, event):
        if event.button == 1:
        
            # Get the x coordinate of the mouse cursor in data coordinates
            ix = event.xdata
            print(ix)
            
            # GOAL: Want to be able to execute:
            # self.textBrowser_X1.setText(str(ix[0])) 
            # where textBrowser_X1 is the name of a line edit widget
            

# 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)

timeseries.py


from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas

class plotData(FigureCanvas):

    def __init__(self, parent=None):
        super().__init__()
        
    def plot(self):
         self.plotWidget.canvas.ax.plot(self.x, self.y)
         self.plotWidget.canvas.draw()

design.py

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1216, 379)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.pushButton_plotData = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_plotData.setGeometry(QtCore.QRect(216, 20, 96, 33))
        font = QtGui.QFont()
        font.setPointSize(14)
        self.pushButton_plotData.setFont(font)
        self.pushButton_plotData.setObjectName("pushButton_plotData")
        self.plotWidget = MplWidget(self.centralwidget)
        self.plotWidget.setGeometry(QtCore.QRect(20, 75, 1177, 234))
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.plotWidget.sizePolicy().hasHeightForWidth())
        self.plotWidget.setSizePolicy(sizePolicy)
        self.plotWidget.setObjectName("plotWidget")
        self.textBrowser_X1 = QtWidgets.QTextBrowser(self.centralwidget)
        self.textBrowser_X1.setGeometry(QtCore.QRect(132, 21, 75, 30))
        self.textBrowser_X1.setObjectName("textBrowser_X1")
        self.label_X1 = QtWidgets.QLabel(self.centralwidget)
        self.label_X1.setGeometry(QtCore.QRect(25, 22, 170, 25))
        font = QtGui.QFont()
        font.setPointSize(14)
        self.label_X1.setFont(font)
        self.label_X1.setObjectName("label_X1")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1216, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.pushButton_plotData.setText(_translate("MainWindow", "Plot Data"))
        self.label_X1.setText(_translate("MainWindow", "X position 1"))

from mplwidget import MplWidget

Upvotes: 0

Views: 472

Answers (1)

eyllanesc
eyllanesc

Reputation: 243897

I see that there are many redundant things. For example because it is necessary that PlotWidget is a QWidget that only has the canvas if the canvas is a QWidget, another example is the class plotData that inherits unnecessarily from FigureCanvas in addition to doing a redundant task.

Considering the above, the solution is:

mplwidget.py

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")


class MplWidget(Canvas):
    def __init__(self, parent=None):
        Canvas.__init__(self, Figure(dpi=100))
        self.setParent(parent)
        self.setSizePolicy(
            QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding
        )
        self.updateGeometry()

        self.ax = self.figure.add_subplot(111)

main.py

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow

import design


class MyApp(QMainWindow, design.Ui_MainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)

        self.x = [1, 2, 3, 4, 5]
        self.y = [1, 2, 3, 4, 5]

        self.pushButton_plotData.clicked.connect(self.plot)
        self.plotWidget.mpl_connect(s="button_press_event", func=self.get_coord)

    def plot(self):
        self.plotWidget.ax.plot(self.x, self.y)
        self.plotWidget.draw()

    def get_coord(self, event):
        if event.button == 1:
            ix = event.xdata
            self.textBrowser_X1.setText(str(ix))


if __name__ == "__main__":

    # Create GUI application
    app = QApplication(sys.argv)
    form = MyApp()
    form.show()
    app.exec_()

Upvotes: 1

Related Questions