Is there a way to change the matplotlib display in a pyqt application ?
I made a destopapplication with 2 radiobuttons, dependinging which button is pressed, i want on radioButton_p graphic1 to be shown and on radioButton_b the graphic2.
I am able to change it from the first button which is pressed to the second, but if the first button is pressed again it will not change back to the graphic of the first button.
Here is my code so far:
from PyQt5 import QtWidgets, QtCore, QtPrintSupport, QtGui
import matplotlib
matplotlib.use("Qt5Agg")
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QVBoxLayout, QSizePolicy, QMessageBox, QWidget
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5.QtWidgets import *
found_words = ["a", "b", "c", "d", "e", "f", "g", "h"]
cound_words = ['1','2','3','4','5','6','7','8']
found_pos = [ 'aaa','ssss']
count_pos = ['2','3']
class MyMplCanvas_begr(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
# self.compute_initial_figure()
self.axes.bar(found_words, cound_words, color=['r', 'b', 'k', 'y', 'g'])
self.axes.set_ylabel('Anzahl')
self.axes.set_xlabel('Begriffe')
self.axes.set_title('hi')
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
class MyMplCanvas_pos(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.plot()
def plot(self):
colors = ['yellowgreen', 'lightcoral']
explode = (0.1, 0) # explode 1st slice
ax = self.figure.add_subplot(111)
ax.pie(count_pos, explode=explode, labels=found_pos, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=140)
class main_statistic(QtWidgets.QWidget):
def __init__(self, parent=None):
super(main_statistic, self).__init__(parent)
self.radioButton_p = QRadioButton('Pos', self)
self.radioButton_p.setGeometry(QtCore.QRect(100, 10, 95, 20))
self.radioButton_p.setCheckable(True)
self.radioButton_p.toggled.connect(self.clicked_pos)
self.radioButton_b = QRadioButton('Word', self)
self.radioButton_b.setGeometry(QtCore.QRect(200, 10, 95, 20))
self.radioButton_b.setCheckable(True)
self.radioButton_b.toggled.connect(self.clicked_begr)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.main_widget = QWidget(self)
self.main_widget.setGeometry(QtCore.QRect(100, 100, 700, 500))
self.main_widget1 = QWidget(self)
self.main_widget1.setGeometry(QtCore.QRect(100, 100, 700, 500))
def clicked_pos(self, down):
if down:
l = QVBoxLayout(self.main_widget)
dc = MyMplCanvas_pos(self.main_widget, width=5, height=4, dpi=100)
l.addWidget(dc)
else:
print('not prssed')
def clicked_begr(self, down):
if down:
l1 = QVBoxLayout(self.main_widget1)
dc1 = MyMplCanvas_begr(self.main_widget1, width=5, height=4, dpi=100)
l1.addWidget(dc1)
else:
print('not prssed2')
Instead of making 2 separate widgets you can add both of the graph widgets to the same layout and hide the one you don't want displayed (this is what i did bellow). Alternatively, you could make a layout and add or remove the widget you want displayed.
working code
from PyQt5 import QtWidgets, QtCore, QtPrintSupport, QtGui
import matplotlib
matplotlib.use("Qt5Agg")
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QVBoxLayout, QSizePolicy, QMessageBox, QWidget, QRadioButton
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5.QtWidgets import *
found_words = ["a", "b", "c", "d", "e", "f", "g", "h"]
cound_words = ['1','2','3','4','5','6','7','8']
found_pos = [ 'aaa','ssss']
count_pos = ['2','3']
class MyMplCanvas_begr(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
# self.compute_initial_figure()
self.axes.bar(found_words, cound_words, color=['r', 'b', 'k', 'y', 'g'])
self.axes.set_ylabel('Anzahl')
self.axes.set_xlabel('Begriffe')
self.axes.set_title('hi')
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
class MyMplCanvas_pos(FigureCanvas):
"""Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self.plot()
def plot(self):
colors = ['yellowgreen', 'lightcoral']
explode = (0.1, 0) # explode 1st slice
ax = self.figure.add_subplot(111)
ax.pie(count_pos, explode=explode, labels=found_pos, colors=colors,
autopct='%1.1f%%', shadow=True, startangle=140)
class main_statistic(QtWidgets.QWidget):
def __init__(self, parent=None):
super(main_statistic, self).__init__(parent)
self.radioButton_p = QRadioButton('Pos', self)
self.radioButton_p.setGeometry(QtCore.QRect(100, 10, 95, 20))
self.radioButton_p.setCheckable(True)
self.radioButton_p.toggled.connect(self.clicked_pos)
self.radioButton_b = QRadioButton('Word', self)
self.radioButton_b.setGeometry(QtCore.QRect(200, 10, 95, 20))
self.radioButton_b.setCheckable(True)
self.radioButton_b.toggled.connect(self.clicked_begr)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.main_widget = QWidget(self)
self.main_widget.setGeometry(QtCore.QRect(100, 100, 700, 500))
#self.editmenu.setHidden(True)
#self.sideMenu.setHidden(False)
l = QVBoxLayout()
self.dc = MyMplCanvas_pos( width=5, height=4, dpi=100)
self.dc.setHidden(True)
l.addWidget(self.dc)
self.dc1 = MyMplCanvas_begr( width=5, height=4, dpi=100)
self.dc1.setHidden(True)
l.addWidget(self.dc1)
self.main_widget.setLayout(l)
def clicked_pos(self):
self.dc.setHidden(False)
self.dc1.setHidden(True)
def clicked_begr(self):
self.dc.setHidden(True)
self.dc1.setHidden(False)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainWin = main_statistic()
mainWin.show()
sys.exit(app.exec_())
Related
Is it possible to use matplotlib checkbuttons in a plot embedded in PyQT5? The code is below, the plot works and it is embedded in a PyQT window but the checkbuttons do not add or remove the series as they should. Code works fine when taken out of PyQT.
import numpy as np
import sys
from matplotlib.widgets import CheckButtons
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout
from PyQt5 import QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.figure = plt.figure()
t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2*np.pi*t)
s1 = np.sin(4*np.pi*t)
s2 = np.sin(6*np.pi*t)
self.figure, ax = plt.subplots()
l0, = ax.plot(t, s0, visible=False, lw=2, color='k', label='2 Hz')
l1, = ax.plot(t, s1, lw=2, color='r', label='4 Hz')
l2, = ax.plot(t, s2, lw=2, color='g', label='6 Hz')
plt.subplots_adjust(left=0.2)
self.lines = [l0, l1, l2]
# Make checkbuttons with all plotted lines with correct visibility
rax = plt.axes([0.05, 0.4, 0.1, 0.15])
self.labels = [str(line.get_label()) for line in self.lines]
visibility = [line.get_visible() for line in self.lines]
check = CheckButtons(rax, self.labels, visibility)
check.on_clicked(self.b)
## print('showing')
## plt.show()
self.canvas = FigureCanvas(self.figure)
layout = QVBoxLayout()
## layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
# layout.addWidget(self.button)
self.setLayout(layout)
self.canvas.draw()
## print('done')
## plt.show()
def b(self,label):
index = self.labels.index(label)
self.lines[index].set_visible(not self.lines[index].get_visible())
plt.draw()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
If you are going to use matplotlib with Qt then you should not use pyplot but the Figure that is set on the canvas. Also "check" must be a member of the class.
Considering the above, the solution is:
from PyQt5.QtWidgets import QApplication, QDialog, QVBoxLayout
import numpy as np
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
from matplotlib.widgets import CheckButtons
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.canvas = FigureCanvas(Figure(figsize=(5, 3)))
t = np.arange(0.0, 2.0, 0.01)
s0 = np.sin(2 * np.pi * t)
s1 = np.sin(4 * np.pi * t)
s2 = np.sin(6 * np.pi * t)
ax = self.canvas.figure.subplots()
(l0,) = ax.plot(t, s0, visible=False, lw=2, color="k", label="2 Hz")
(l1,) = ax.plot(t, s1, lw=2, color="r", label="4 Hz")
(l2,) = ax.plot(t, s2, lw=2, color="g", label="6 Hz")
self.canvas.figure.subplots_adjust(left=0.2)
self.lines = [l0, l1, l2]
rax = self.canvas.figure.add_axes([0.05, 0.4, 0.1, 0.15])
self.labels = [str(line.get_label()) for line in self.lines]
visibility = [line.get_visible() for line in self.lines]
self.check = CheckButtons(rax, self.labels, visibility)
self.check.on_clicked(self.on_clicked)
lay = QVBoxLayout(self)
lay.addWidget(self.canvas)
self.resize(640, 480)
def on_clicked(self, label):
index = self.labels.index(label)
self.lines[index].set_visible(not self.lines[index].get_visible())
self.canvas.draw()
def main():
import sys
app = QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I am looking for a way to create a grid of graphs that can be dragged/dropped to rearrange the order. My first try was using QDockWidgets as they allow for drag/drop, however they were limited in a lot of other ways. Would it be possible to implement this function in a QGridLayout?
For now I have a QGridLayout with 3x3 matplotlib widgets.
Here is an example of the desired layout outcome.
Sample code:
import sys
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import random
from PyQt5.QtWidgets import QGridLayout, QVBoxLayout, QHBoxLayout, QScrollArea, QWidget, QDialog, QApplication, QFrame
class IndicSelectWindow(QDialog):
def __init__(self, parent=None):
super(IndicSelectWindow, self).__init__(parent=parent)
self.resize(1000, 800)
self.layout = QtWidgets.QHBoxLayout(self)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.layout.addWidget(self.scrollArea)
for i in range(3):
for j in range(3):
self.Frame = QFrame(self)
self.Frame.setStyleSheet("background-color: white;")
self.Frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.Frame.setLineWidth(2)
self.layout = QHBoxLayout(self.Frame)
self.figure = Figure() # a figure to plot on
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111) # create an axis
data = [random.random() for i in range(10)]
self.ax.plot(data, '*-') # plot data
self.canvas.draw() # refresh canvas
self.layout.addWidget(self.canvas)
Box = QVBoxLayout()
Box.addWidget(self.Frame)
self.gridLayout.addLayout(Box, i, j)
self.gridLayout.setColumnStretch(i % 3, 1)
self.gridLayout.setRowStretch(j, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = IndicSelectWindow()
w.show()
sys.exit(app.exec_())
Here is an implementation that will swap the positions of the items involved in a drag/drop. The 3 main steps are:
(1) Reimplement mousePressEvent to get the index of the LayoutItem based on mouse coordinates.
(2) Reimplement mouseMoveEvent to set up a QDrag of the FigureCanvas.
(3) Reimplement dropEvent to swap the target items in the layout.
Since the matplotlib widgets absorb mouse events you also need to reimplement eventFilter to detect them.
import sys, random
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
class IndicSelectWindow(QDialog):
def __init__(self, parent=None):
super(IndicSelectWindow, self).__init__(parent=parent)
self.resize(1000, 800)
self.target = None
self.setAcceptDrops(True)
self.layout = QHBoxLayout(self)
self.scrollArea = QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.layout.addWidget(self.scrollArea)
for i in range(3):
for j in range(3):
self.Frame = QFrame(self)
self.Frame.setStyleSheet("background-color: white;")
self.Frame.setFrameStyle(QFrame.Panel | QFrame.Raised)
self.Frame.setLineWidth(2)
self.layout = QHBoxLayout(self.Frame)
self.figure = Figure() # a figure to plot on
self.canvas = FigureCanvas(self.figure)
self.ax = self.figure.add_subplot(111) # create an axis
data = [random.random() for i in range(10)]
self.ax.plot(data, '*-') # plot data
self.canvas.draw() # refresh canvas
self.canvas.installEventFilter(self)
self.layout.addWidget(self.canvas)
Box = QVBoxLayout()
Box.addWidget(self.Frame)
self.gridLayout.addLayout(Box, i, j)
self.gridLayout.setColumnStretch(i % 3, 1)
self.gridLayout.setRowStretch(j, 1)
def eventFilter(self, watched, event):
if event.type() == QEvent.MouseButtonPress:
self.mousePressEvent(event)
elif event.type() == QEvent.MouseMove:
self.mouseMoveEvent(event)
elif event.type() == QEvent.MouseButtonRelease:
self.mouseReleaseEvent(event)
return super().eventFilter(watched, event)
def get_index(self, pos):
for i in range(self.gridLayout.count()):
if self.gridLayout.itemAt(i).geometry().contains(pos) and i != self.target:
return i
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.target = self.get_index(event.windowPos().toPoint())
else:
self.target = None
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton and self.target is not None:
drag = QDrag(self.gridLayout.itemAt(self.target))
pix = self.gridLayout.itemAt(self.target).itemAt(0).widget().grab()
mimedata = QMimeData()
mimedata.setImageData(pix)
drag.setMimeData(mimedata)
drag.setPixmap(pix)
drag.setHotSpot(event.pos())
drag.exec_()
def mouseReleaseEvent(self, event):
self.target = None
def dragEnterEvent(self, event):
if event.mimeData().hasImage():
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if not event.source().geometry().contains(event.pos()):
source = self.get_index(event.pos())
if source is None:
return
i, j = max(self.target, source), min(self.target, source)
p1, p2 = self.gridLayout.getItemPosition(i), self.gridLayout.getItemPosition(j)
self.gridLayout.addItem(self.gridLayout.takeAt(i), *p2)
self.gridLayout.addItem(self.gridLayout.takeAt(j), *p1)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = IndicSelectWindow()
w.show()
sys.exit(app.exec_())
I am trying to get the "Game Name:" (QLabel), input box (QLineEdit), and QPushButton on one line and the "Pop-up" QLabel) to appear on the bottom
but am having difficulties with get QGridLayout to work
With this code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QLabel, QLineEdit, QGridLayout, QGroupBox, QDialog
from PyQt5.QtCore import pyqtSlot
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Project PiBu!!")
self.createGridLayout()
self.windowLayout = QVBoxLayout()
self.windowLayout.addWidget(self.horizontalGroupBox)
self.setLayout(self.windowLayout)
self.game_name = QLabel("Game Name:", self)
self.game_line_edit = QLineEdit(self)
self.search_button = QPushButton("Search", self)
self.search_button.clicked.connect(self.on_click)
self.game = QLabel(self)
self.show()
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox()
self.layout = QGridLayout()
self.layout.setColumnStretch(1, 4)
self.layout.setColumnStretch(2, 4)
self.layout.addWidget(self.game_name, 0, 0)
self.layout.addWidget(self.game_line_edit, 0, 1)
self.layout.addWidget(self.search_button, 0, 2)
self.layout.addWidget(self.game, 1, 0)
self.horizontalGroupBox.setLayout(layout)
#pyqtSlot()
def on_click(self):
self.game.setText(self.game_line_edit.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
I am getting this error:
AttributeError: 'Window' object has no attribute 'game_name'
Why?
have a feeling its something simple rather than something more complicated but maybe I'm wrong
Please help!!!
Thank you!
You call the createGridLayout method earlier than you define the variables used in it.
import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QHBoxLayout,
QVBoxLayout, QPushButton, QLabel, QLineEdit,
QGridLayout, QGroupBox, QDialog)
from PyQt5.QtCore import pyqtSlot
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.setWindowTitle("Project PiBu!!")
# self.createGridLayout()
# self.windowLayout = QVBoxLayout()
# self.windowLayout.addWidget(self.horizontalGroupBox)
# self.setLayout(self.windowLayout)
self.game_name = QLabel("Game Name:", self)
self.game_line_edit = QLineEdit(self)
self.search_button = QPushButton("Search", self)
self.search_button.clicked.connect(self.on_click)
self.game = QLabel(self)
self.createGridLayout() # < --
self.windowLayout = QVBoxLayout() # < --
self.windowLayout.addWidget(self.horizontalGroupBox) # < --
self.setLayout(self.windowLayout) # < --
self.show()
def createGridLayout(self):
self.horizontalGroupBox = QGroupBox()
self.layout = QGridLayout()
self.layout.setColumnStretch(1, 4)
self.layout.setColumnStretch(2, 4)
# AttributeError: 'Window' object has no attribute 'game_name'
self.layout.addWidget(self.game_name, 0, 0)
self.layout.addWidget(self.game_line_edit, 0, 1)
self.layout.addWidget(self.search_button, 0, 2)
self.layout.addWidget(self.game, 1, 0)
self.horizontalGroupBox.setLayout(self.layout) # +++ self.
#pyqtSlot()
def on_click(self):
self.game.setText(self.game_line_edit.text())
if __name__ == '__main__':
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
The multicursor example
The question is : If I want the plot to be displayed on a tab of the QTabWidget,how to make the MultiCursor works?
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
import numpy as np
import sys
from matplotlib.gridspec import GridSpec
from matplotlib.widgets import MultiCursor
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
class MainWindow(QMainWindow):
def __init__(self):
super().__init__(flags=Qt.Window)
self.setFont(QFont("Microsoft YaHei", 10, QFont.Normal))
self.setMinimumSize(1550, 950)
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
centralwidget = QWidget(flags=Qt.Widget)
centralwidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.setCentralWidget(centralwidget)
self.tabview = QTabWidget()
self.tabview.currentChanged.connect(self.onchange)
self.chart_widget0 = QWidget()
self.chart_widget1 = QWidget()
self.dc0 = my_Canvas(self.chart_widget0, width=20, height=8, dpi=100)
self.dc1 = my_Canvas(self.chart_widget1, width=20, height=8, dpi=100)
self.tabview.addTab(self.dc0, "MultiCursor")
self.tabview.addTab(self.dc1, "Cursor")
toplayout = QHBoxLayout()
toplayout.addWidget(self.tabview)
centralwidget.setLayout(toplayout)
def onchange(self,i):
if i == 0:
self.dc0.update_figure()
elif i == 1:
self.dc1.update_figure()
class my_Canvas(FigureCanvas):
def __init__(self, parent=None, width=10, height=7, dpi=100):
self.fig = plt.figure(figsize=(width, height), dpi=dpi)
gs = GridSpec(2, 1, height_ratios=[3, 1])
self.axes1 = plt.subplot(gs[0])
self.axes2 = plt.subplot(gs[1])
self.compute_initial_figure()
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
def compute_initial_figure(self):
self.axes1.cla()
self.axes2.cla()
def update_figure(self):
t = np.arange(0.0, 2.0, 0.01)
s1 = np.sin(2*np.pi*t)
s2 = np.sin(4*np.pi*t)
self.axes1.plot(t, s1)
self.axes2.plot(t, s2)
multi = MultiCursor(self.fig.canvas, (self.axes1, self.axes2), color='r', lw=1)
self.draw()
if __name__ == '__main__':
app = QApplication(sys.argv)
w1 = MainWindow()
w1.show()
sys.exit(app.exec_())
How to modify the code to make the MultiCursor works, and could I control the display of the cursor by key or mousebutton click?
Further more, how to display the coordinate with the cursor?
As the Multicursor documentation tells us,
For the cursor to remain responsive you must keep a reference to it.
The easiest way is to make it a class variable,
self.multi = MultiCursor(...)
I have a Widget into my GUI hosting a scatterplot graphic. I managed to include a pick event but am not able to get the x y coordinate by clicking a plot only the print('yahoo') works. My code is based on the following article: see link (section: Simple picking example).
How can I get the coordinates of the point (e.g. x=20 and y=50 which is one my five points) by clicking the point on the scatterplot?
Front-end code:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(595, 393)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setMaximumSize(QtCore.QSize(100, 16777215))
self.pushButton.setObjectName("pushButton")
self.gridLayout.addWidget(self.pushButton, 0, 0, 1, 1)
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setMinimumSize(QtCore.QSize(0, 200))
self.widget.setStyleSheet("background-color: rgb(255, 255, 255);")
self.widget.setObjectName("widget")
self.gridLayout.addWidget(self.widget, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 595, 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.setText(_translate("MainWindow", "PushButton"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Back-end code:
import sys
import matplotlib.pyplot as plt
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QSizePolicy
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
from front_end import Ui_MainWindow
class Graph_init(FigureCanvas):
def __init__(self, parent=None):
fig = Figure()
fig.patch.set_facecolor("None")
self.axes = fig.add_subplot(111)
self.compute_initial_figure()
FigureCanvas.__init__(self, fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
FigureCanvas.mpl_connect(self, 'pick_event', self.onclick)
def onclick(self, event):
print('yahoo')
thisline = self.event.artist
xdata = thisline.get_xdata()
ydata = thisline.get_ydata()
class Graph_populate(Graph_init):
def compute_initial_figure(self):
x = [10,20,30,40,50]
y = [100,50,150,200,75]
size = [1000,2000,3000,5000,2000]
self.axes.scatter(x,y,s=size,color='blue', picker=1)
self.axes.patch.set_facecolor('None')
class GUI(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(GUI, self).__init__(parent)
self.setupUi(self)
self.sc = Graph_populate(self.widget)
self.gridLayout.addWidget(self.sc, 0, 1, 1, 1)
if __name__ == '__main__':
app = QApplication(sys.argv)
prog = GUI()
prog.showMaximized()
sys.exit(app.exec_())
Thank you
You are plotting a scatterplot. Hence you may have a look at the third part of the pick_event_demo, where a scatterplot is treated.
The idea would be to get the index of the picked datapoint and take the data at that index out to obtain the coordinates.
def onclick(self, event):
ind = event.ind[0]
data = event.artist.get_offsets()
xdata, ydata = data[ind,:]
print ((xdata, ydata))
Note that those are the coordintes of the data point, not those of the mouseclick (which is how I understand the question).