Python 2.7 Qt Matplotlib : subplot ID reference from event - python

My goal is to identify which subplot has been clicked on by the user. More precisely in the matplotlib class, I can identify the subplot using event.inaxes. Great. But I cannot get that event in the Qt widget class.
I am definitely missing something ...
Here is the code with my latest "awkward" attempt. Any suggestion on how to procceed ?
I am no Python expert. Python 2.7 has to be used (no choice)
from __future__ import print_function
from __future__ import division
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from matplotlib.figure import Figure
from matplotlib.backend_bases import key_press_handler
from matplotlib.backend_bases import Event
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
#Connect InventoryChartsWidget to ChartFigure: QT
class TheConnector(QtCore.QObject):
selecteddataregion=pyqtSignal(name='selecteddataregion')
def emitsignal(self,xmin,xmax,ymin,ymax):
self.selecteddataregion.emit()
#Chart including events: MATPLOTLIB
class ChartFigure(Figure):
def onclick(self,event):
#MAIN ISSUE
#HOW TO RETURN THE subplot axes to class InventoryChartsWidget?
if event.button==1 :
self.ConnSbPlt.emitsignal(1.0,1.0,2.0,2.0)
print('OK: Axes is ... ', event.inaxes)
def __init__(self,Conn):
#Init the Matplotlib
Figure.__init__(self) #initialize the orginal class, see also super()
super(ChartFigure, self).__init__()
self.canvas=FigureCanvas(self)
self.ConnSbPlt=Conn
#Chart including events: QT
class InventoryChartsWidget(QtGui.QDialog):
def __init__(self, parent=None,xlimlow=0,xlimhigh=100,ylimlow=0,ylimhigh=100, G_array=[], N_array=[], ddom_array=[], hdom_array=[], speciesDict={}):
QMainWindow.__init__(self, parent)
#Fake stupid data
self.mG_array = [2] * 10
self.mHdom_array = [0.5] * 10
#jte to make sur I have it
self.xdata_start=-1.0
#fake plot to get a member of type subplot: UGLY!
#Attempt to create a member object "axes"
self.tabFake = QtGui.QWidget()
self.tabFake = self.create_tab(self.tabFake)
self.tabFake.plots = []
self.subPlotFake = self.tabFake.fig.add_subplot(111)
print("here is OK; it exists ...", self.subPlotFake)
self.create_main_frame()
self.setModal(False)
self.setVisible(True)
self.show()
def create_main_frame(self):
#Associate a Qwidget with the InventoryChartsWidget widget
print("OK here too; it exists ... ",self.subPlotFake)
self.main_frame = QtGui.QWidget()
LesTabs = QtGui.QTabWidget()
self.tabG = QtGui.QWidget()
#Fill the tab with Matplotlib object and draw the charts
self.tabG=self.create_tab(self.tabG)
self.on_draw_G(self.tabG)
self.tabG.fig.subplots_adjust(left=0.02,bottom=0.05,right=1,top=0.95,wspace=0.2,hspace=0.2)
LesTabs.addTab(self.tabG,"Chart")
grid = QGridLayout()
grid.addWidget(LesTabs, 0, 0)
self.main_frame.setLayout(grid)
self.setLayout(grid)
self.layout().addWidget(self.main_frame)
def UpdatePlot_DataSelection(self):
#SLOT
print("Get connected here process the data in the subplot XX...")
def on_draw_G(self,tab):
#Juts one subplot for test purpose
tab.fig.clear()
tab.plots = []
subPlot = tab.fig.add_subplot(111)
subPlot.hold(False)
tab.plots.append(subPlot)
self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
subPlot = tab.fig.add_subplot(122)
subPlot.hold(False)
tab.plots.append(subPlot)
self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
tab.canvas.draw()
def create_tab(self,tab):
#Create the tab widget, associated with Matplotlib plot
print("OK member exists ... ", self.xdata_start)
print("OK member exists ",self.tabFake)
#ISSUE HERE: don't understand
#print("NOT OK !!! member does not exist Why ? ",self.subPlotFake)
Conn=TheConnector()
#MATPLOTLIB
tab.fig = ChartFigure(Conn)
tab.canvas = FigureCanvas(tab.fig)
tab.canvas.setParent(tab)
tab.canvas.setFocusPolicy(Qt.StrongFocus)
tab.canvas.setFocus()
#connect signal to slot
Conn.selecteddataregion.connect(self.UpdatePlot_DataSelection)
tab.mpl_toolbar = NavigationToolbar(tab.canvas, tab)
vbox = QVBoxLayout()
vbox.addWidget(tab.canvas)
vbox.addWidget(tab.mpl_toolbar)
tab.setLayout(vbox)
tab.canvas.mpl_connect('button_press_event', tab.fig.onclick)
return tab
def on_key_press(self, event):
#Keyboard input: standard mpl key press
key_press_handler(event, self.canvas, self.mpl_toolbar)
def PlotData_G(self, plot, G_array, hdom_array):
# Plot G
plot.hold(False)
plot.scatter(x=hdom_array, y=G_array, marker='+',linewidths=1.5)
plot.set_autoscaley_on(True)
plot.tick_params(labelsize=8)
def main():
app = QApplication(sys.argv)
form = InventoryChartsWidget(xlimlow=0,xlimhigh=60,ylimlow=0,ylimhigh=80)
form.show()
app.exec_()
if __name__ == "__main__":
main()
There are 3 classes:
TheConnector is a Signal/Slot QT class
ChartFigure is matplotlib class (including the desired mouse Event)
InventoryChartsWidget is the main widget (Qt; here I need the ID of the subplot)
Any help would be greatly appreciated. Thank you.

Here is a working solution. The true limit was my thinking in python (to be more specific the lack of properly declared variables ... can't get use to it)
from __future__ import print_function
from __future__ import division
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from matplotlib.figure import Figure
from matplotlib.backend_bases import key_press_handler
from matplotlib.backend_bases import Event
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
#Connect InventoryChartsWidget to ChartFigure: QT
class TheConnector(QtCore.QObject):
selecteddataregionARG=pyqtSignal(object,name='selecteddataregionIN')
def emitsignalEvent(self,TheEvent):
self.selecteddataregionARG.emit(TheEvent)
#Chart including events: MATPLOTLIB
class ChartFigure(Figure):
def onclick(self,event):
#MAIN ISSUE
#HOW TO RETURN THE subplot axes to class InventoryChartsWidget class?
if event.button==1 :
print('Event: Axes is ... ', event.inaxes)
self.ConnSbPlt.emitsignalEvent(event.inaxes)
def __init__(self,Conn):
#Init the Matplotlib
Figure.__init__(self) #initialize the orginal class, see also super()
super(ChartFigure, self).__init__()
self.canvas=FigureCanvas(self)
self.ConnSbPlt=Conn
#Chart including events: QT
class InventoryChartsWidget(QtGui.QDialog):
def __init__(self, parent=None,xlimlow=0,xlimhigh=100,ylimlow=0,ylimhigh=100, G_array=[], N_array=[], ddom_array=[], hdom_array=[], speciesDict={}):
QMainWindow.__init__(self, parent)
#Fake stupid data
self.mG_array = [2] * 10
self.mHdom_array = [0.5] * 10
#jte to make sur I have it
self.xdata_start=-1.0
self.create_main_frame()
self.setModal(False)
self.setVisible(True)
self.show()
def create_main_frame(self):
#Associate a Qwidget with the InventoryChartsWidget widget
self.main_frame = QtGui.QWidget()
LesTabs = QtGui.QTabWidget()
self.tabG = QtGui.QWidget()
#Fill the tab with Matplotlib object and draw the charts
self.tabG=self.create_tab(self.tabG)
self.on_draw_G(self.tabG)
self.tabG.fig.subplots_adjust(left=0.02,bottom=0.05,right=1,top=0.95,wspace=0.2,hspace=0.2)
LesTabs.addTab(self.tabG,"Chart")
grid = QGridLayout()
grid.addWidget(LesTabs, 0, 0)
self.main_frame.setLayout(grid)
self.setLayout(grid)
self.layout().addWidget(self.main_frame)
def UpdatePlot_DataSelection_withArg(self,TheEvent):
#SLOT
print("WITH ARG : Get connected here process the data in the subplot XX...",TheEvent)
def on_draw_G(self,tab):
#Juts one subplot for test purpose
tab.fig.clear()
tab.plots = []
subPlot = tab.fig.add_subplot(111)
subPlot.hold(False)
tab.plots.append(subPlot)
self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
subPlot = tab.fig.add_subplot(122)
subPlot.hold(False)
tab.plots.append(subPlot)
self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
tab.canvas.draw()
def create_tab(self,tab):
#Create the tab widget, associated with Matplotlib plot
Conn=TheConnector()
#MATPLOTLIB
tab.fig = ChartFigure(Conn)
tab.canvas = FigureCanvas(tab.fig)
tab.canvas.setParent(tab)
tab.canvas.setFocusPolicy(Qt.StrongFocus)
tab.canvas.setFocus()
#connect signal to slot
Conn.selecteddataregionARG.connect(lambda who="Three": self.UpdatePlot_DataSelection_withArg(who))
tab.mpl_toolbar = NavigationToolbar(tab.canvas, tab)
vbox = QVBoxLayout()
vbox.addWidget(tab.canvas)
vbox.addWidget(tab.mpl_toolbar)
tab.setLayout(vbox)
tab.canvas.mpl_connect('button_press_event', tab.fig.onclick)
return tab
def on_key_press(self, event):
#Keyboard input: standard mpl key press
key_press_handler(event, self.canvas, self.mpl_toolbar)
def PlotData_G(self, plot, G_array, hdom_array):
# Plot G
plot.hold(False)
plot.scatter(x=hdom_array, y=G_array, marker='+',linewidths=1.5)
plot.set_autoscaley_on(True)
def main():
app = QApplication(sys.argv)
form = InventoryChartsWidget(xlimlow=0,xlimhigh=60,ylimlow=0,ylimhigh=80)
form.show()
app.exec_()
if __name__ == "__main__":
main()
Maybe it can help someone ...
We can of course argue if the 3 classes make sense but this is another topic.

Here is how you could transfer the event to the main class:
from __future__ import print_function
from __future__ import division
import sys
from PyQt4 import QtGui
from PyQt4 import QtCore
from matplotlib.figure import Figure
from matplotlib.backend_bases import key_press_handler
from matplotlib.backends.backend_qt4agg import (
FigureCanvasQTAgg as FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
#Connect InventoryChartsWidget to ChartFigure: QT
class TheConnector(QtCore.QObject):
selecteddataregion=QtCore.pyqtSignal(object, name='selecteddataregion')
def emitsignal(self,xmin,xmax,ymin,ymax, event):
self.selecteddataregion.emit((xmin,xmax,ymin,ymax, event))
#Chart including events: MATPLOTLIB
class ChartFigure(Figure):
def onclick(self,event):
#MAIN ISSUE
#HOW TO RETURN THE subplot axes to class InventoryChartsWidget?
if event.button==1 :
print('OK: Axes is ... ', event.inaxes)
self.ConnSbPlt.emitsignal(1.0,1.0,2.0,2.0, event)
def __init__(self,Conn):
#Init the Matplotlib
Figure.__init__(self) #initialize the orginal class, see also super()
super(ChartFigure, self).__init__()
self.canvas=FigureCanvas(self)
self.ConnSbPlt=Conn
#Chart including events: QT
class InventoryChartsWidget(QtGui.QDialog):
def __init__(self, parent=None,xlimlow=0,xlimhigh=100,ylimlow=0,ylimhigh=100, G_array=[], N_array=[], ddom_array=[], hdom_array=[], speciesDict={}):
QtGui.QMainWindow.__init__(self, parent)
#Fake stupid data
self.mG_array = [2] * 10
self.mHdom_array = [0.5] * 10
#jte to make sur I have it
self.xdata_start=-1.0
#fake plot to get a member of type subplot: UGLY!
#Attempt to create a member object "axes"
self.tabFake = QtGui.QWidget()
self.tabFake = self.create_tab(self.tabFake)
self.tabFake.plots = []
self.subPlotFake = self.tabFake.fig.add_subplot(111)
print("here is OK; it exists ...", self.subPlotFake)
self.create_main_frame()
self.setModal(False)
self.setVisible(True)
self.show()
def create_main_frame(self):
#Associate a Qwidget with the InventoryChartsWidget widget
print("OK here too; it exists ... ",self.subPlotFake)
self.main_frame = QtGui.QWidget()
LesTabs = QtGui.QTabWidget()
self.tabG = QtGui.QWidget()
#Fill the tab with Matplotlib object and draw the charts
self.tabG=self.create_tab(self.tabG)
self.on_draw_G(self.tabG)
self.tabG.fig.subplots_adjust(left=0.02,bottom=0.05,right=1,top=0.95,wspace=0.2,hspace=0.2)
LesTabs.addTab(self.tabG,"Chart")
grid = QtGui.QGridLayout()
grid.addWidget(LesTabs, 0, 0)
self.main_frame.setLayout(grid)
self.setLayout(grid)
self.layout().addWidget(self.main_frame)
def UpdatePlot_DataSelection(self, transfer_object):
#SLOT
xmin,xmax,ymin,ymax, event = transfer_object
print ("Axes are now in the InventoryChartsWidget: ", event.inaxes)
def on_draw_G(self,tab):
#Juts one subplot for test purpose
tab.fig.clear()
tab.plots = []
subPlot = tab.fig.add_subplot(111)
#subPlot.hold(False)
tab.plots.append(subPlot)
self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
subPlot = tab.fig.add_subplot(122)
#subPlot.hold(False)
tab.plots.append(subPlot)
self.PlotData_G(subPlot,self.mG_array,self.mHdom_array)
tab.canvas.draw()
def create_tab(self,tab):
#Create the tab widget, associated with Matplotlib plot
print("OK member exists ... ", self.xdata_start)
print("OK member exists ",self.tabFake)
#ISSUE HERE: don't understand
#print("NOT OK !!! member does not exist Why ? ",self.subPlotFake)
# reason: self.subPlotFake does not yet exist
Conn=TheConnector()
#MATPLOTLIB
tab.fig = ChartFigure(Conn)
tab.canvas = FigureCanvas(tab.fig)
tab.canvas.setParent(tab)
tab.canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
tab.canvas.setFocus()
#connect signal to slot
Conn.selecteddataregion.connect(self.UpdatePlot_DataSelection)
tab.mpl_toolbar = NavigationToolbar(tab.canvas, tab)
vbox = QtGui.QVBoxLayout()
vbox.addWidget(tab.canvas)
vbox.addWidget(tab.mpl_toolbar)
tab.setLayout(vbox)
tab.canvas.mpl_connect('button_press_event', tab.fig.onclick)
return tab
def on_key_press(self, event):
#Keyboard input: standard mpl key press
key_press_handler(event, self.canvas, self.mpl_toolbar)
def PlotData_G(self, plot, G_array, hdom_array):
# Plot G
#plot.hold(False) #axes.hold is deprecated.
plot.scatter(x=hdom_array, y=G_array, marker='+',linewidths=1.5)
plot.set_autoscaley_on(True)
plot.tick_params(labelsize=8)
def main():
app = QtGui.QApplication(sys.argv)
form = InventoryChartsWidget(xlimlow=0,xlimhigh=60,ylimlow=0,ylimhigh=80)
form.show()
app.exec_()
if __name__ == "__main__":
main()

Related

How to reset/ start a new polygon with embeded matplotlib in pyqt

I am trying to create a polygon selector in my PySide2 application. Selector is working fine, but then I want to add functionality to reset/start new polygon when escape button is pressed. Something similar to this PolygonSelector example, when escape is pressed.
https://matplotlib.org/stable/gallery/widgets/polygon_selector_demo.html
I tried method .clear() but it does not seems to work for me.
import sys
import numpy as np
from PySide2 import QtWidgets, QtGui
from matplotlib.backends.backend_qtagg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
from matplotlib.widgets import PolygonSelector
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
shortcut_clear_selection = QtWidgets.QShortcut(QtGui.QKeySequence("Escape"), self._main)
shortcut_clear_selection.activated.connect(self.callback_clear_selection)
layout = QtWidgets.QVBoxLayout(self._main)
static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
layout.addWidget(NavigationToolbar(static_canvas, self))
layout.addWidget(static_canvas)
ax = static_canvas.figure.subplots()
t = np.linspace(0, 10, 501)
ax.plot(t, np.tan(t), ".")
self.poly = PolygonSelector(ax, self.onselect)
def onselect(self, verts):
pass
def callback_clear_selection(self):
# HERE should be the reset part
self.poly.clear()
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
app.activateWindow()
app.raise_()
qapp.exec_()
Problem is, that ESC key release event is not handled by PolygonSelector but Your callback. Therefore, to clear polygon and restart creation of polygon You have to clear polygon data and show selector again. clear method was just hiding selector, but polygon data stayed unchanged.
Change Your callback code into this:
def callback_clear_selection(self):
# HERE should be the reset
self.poly._xs, self.poly._ys = [0], [0]
self.poly._selection_completed = False
self.poly.set_visible(True)
Now, when You press ESC, polygon should be removed and You can start selection of new one.

Redraw matplotlib figure after updating Line2D properties through PyQt5 GUI

In the following minimal-example GUI, I have a button and a plot window containing 2 lines. When the user clicks on the button, I want the linewidth of both lines to be changed, after which the plot should be redrawn.
When I click the button, I get a TypeError for the draw() command:
Traceback (most recent call last):
File "minimal_plot.py", line 55, in updatePlot
self.sc.ax.draw()
TypeError: draw_wrapper() missing 1 required positional argument: 'renderer'
I never had to pass arguments to draw() before. What should I put there?
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qt import *
import matplotlib
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None):
fig = Figure(figsize=(10, 10), dpi=100)
self.ax = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
# --- Define layout ---
layout1 = QVBoxLayout()
btn = QPushButton('', self)
btn.clicked.connect(self.updatePlot)
layout1.addWidget(btn)
# Plot section
self.sc = MplCanvas(self)
layout1.addWidget(self.sc)
self.sc.setFixedHeight(600)
self.sc.setFixedWidth(600)
self.show()
widget = QWidget()
widget.setLayout(layout1)
self.setCentralWidget(widget)
# Create some lines
self.sc.ax.plot([0,1,2,3,4], [10,1,20,3,40])
self.sc.ax.plot([0,1,2,3,4], [9,0,19,2,39])
def updatePlot(self):
lines = self.sc.ax.get_lines()
for i in range(len(lines)):
lines[i].set_linewidth(4)
self.sc.ax.draw()
# Fix to make PyQt5 close correctly in Spyder
def closeEvent(self,event):
QApplication.quit()
# Run main code
app = QApplication.instance()
window = MainWindow()
window.show()
app.exec_()
Note: the code may differ slightly from a normal PyQt5 application because I run it in Spyder (that's why I invoke app = Qapplication.instance() instead of app = Qapplication([]). The closeEvent() definition can also be removed if one does not use Spyder.

Plotting with a for loop in matplotlib, with lists

form_class = uic.loadUiType("GUI.ui")[0] # Load the UI
class MainWindowClass(QtGui.QMainWindow, form_class):
def __init__(self, target, Afb, np, conversion, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.setupUi(self)
if self.RadioButton.isChecked():
Ids, Ugs = unipolar_steuerkennlinie(self.target, self.Afb, self.np, self.conversion)
def plot_matplotlibwidget(self, *args):
for x in range(0, 40):
self.matplotlibwidget.axes.plot([args[0][x]], [[args[1][x]]])
self.matplotlibwidget.axes.figure.canvas.draw_idle()
Hi, I have this function and I don't really know how to plot correctly. Now it shows nothing but the does change the scale.
Since it is hard to completely replicate your code and error, I've created you a simple minimal GUI that has a MPL widget and draws a few random lines.
from PyQt4 import QtGui, QtCore
import sys
import functools
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
import numpy as np
from matplotlib.figure import Figure
class test(QtGui.QWidget):
def __init__(self,parent=None):
self.widget=QtGui.QWidget.__init__(self, parent)
# Button to plot
self.btnPlot = QtGui.QPushButton('Plot')
self.btnPlot.connect(self.btnPlot, QtCore.SIGNAL('clicked()'), self.btnPlotPressed)
# Line edit for number of lines
self.qleN = QtGui.QLineEdit(str(0))
# Create canvas
self.setupMPLWidget()
# Layout
self.hbox = QtGui.QHBoxLayout()
self.hbox.addWidget(self.btnPlot)
self.hbox.addWidget(self.qleN)
self.hbox.addWidget(self.canvas)
self.setLayout(self.hbox)
self.show()
def btnPlotPressed(self):
"""Plots a few lines."""
# Get number of buttons to add
n=int(self.qleN.text())
# Generate some data
xs,ys=self.randData(n)
# Plot
self.plot_matplotlibwidget(xs,ys)
def randData(self,n):
"""Creates n random data sets."""
ys=[]
xs=[]
for i in range(n):
xs.append(np.arange(n-i))
ys.append(np.random.random(size=xs[-1].shape))
return xs,ys
def plot_matplotlibwidget(self,*args):
"""Plots list of datasets."""
for x in range(0, len(args[0])):
self.ax.plot(args[0][x], args[1][x])
self.ax.figure.canvas.draw_idle()
def setupMPLWidget(self):
"""Sets up a MPL figure to draw on."""
# Create parenting widget
self.plotFrame = QtGui.QWidget()
self.plotFrame.setMaximumWidth(1)
# Create Figure
self.fig = Figure( dpi=100)
#self.fig.set_size_inches(100,100,forward=True)
self.canvas = FigureCanvas(self.fig)
self.canvas.setParent(self.plotFrame)
self.ax = self.fig.add_subplot(111)
def main():
#Creating application
app = QtGui.QApplication(sys.argv)
main_win = test()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
It has a little QLE where you can specify how many lines you want to draw. I hope this helps.

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_())
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]))

Expediting matplotlib's scatter function in a pyqt wrapper

I am trying to plot real-time data using matplotlib's scatter function (~200 fps) with a pyqt wrapper. Each frame consists of around 1000 points. However, I get a maximum of around 7 or 8 frames per second. My code is as follows:
import sys
import random
import types
import re
import sys
import os
import matplotlib.pyplot as plt
from PyQt4 import QtGui, QtCore
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib import pyplot as plt
from time import sleep
class Window(QtGui.QDialog):
def __init__(self, increment=10, nSteps=500, timestep=0.0004, parent=None):
super(Window, self).__init__(parent)
# frame increment
self.increment = increment
self.nSteps = nSteps
self.timestep = timestep # in seconds
# a figure instance to plot on
self.figure = plt.figure()
self.ax1 = self.figure.add_subplot(1, 1, 1)
# 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.start)
# the current frame
self.index = 0
# set the layout
layout = QtGui.QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
self.setLayout(layout)
def start(self):
# connects timer to dynamic plot
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.updatePlot)
self.timer.start(100)
def updatePlot(self):
if self.index > self.increment*self.nSteps:
self.timer.stop()
return
data = [["ghost_points.dat", "green"], ["wall_points.dat", "red"], [("mps.%s.out") % self.index, "blue"]]
self.index += self.increment
self.ax1.cla() # clear axes
for i in data:
<gets x and y data and color>
self.ax1.scatter(x, y, c=color)
self.canvas.draw()
def mpsPlot():
app = QtGui.QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
if __name__ == "__main__":
mpsPlot()
I've looked at several other sources online, but none of them have provided substantial answers that have helped me in my goal. Is there any way to speed up my code to reach ~250 fps? If not, are there any alternatives to matplotlib that will allow me to reach this speed?

Categories