I want to generate a scatterplot (up to half a million points) and on top of that, add different statistics (e.g. Q1, median, Q3). The idea is to add/delete those statistics without replotting the scatterplot in order to speed up the process. So far I can add plots independently on the figure but I can't delete a specific plot.
When I uncheck the checkbox, I get the following error:
AttributeError: 'Graphics' object has no attribute 'vline1'
I understand that when I create the plot, I need to store/return the plot in order to call it later when I want to delete it but I don't know how to do that.
Here my current code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
class Mainwindow(QMainWindow):
def __init__(self, parent=None):
super(Mainwindow, self).__init__(parent)
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.gridLayout = QGridLayout(centralWidget)
self.gridLayout.addWidget(self.canvas)
self.btn_plot = QCheckBox("Plot")
self.btn_line = QCheckBox("Line")
self.gridLayout.addWidget(self.btn_plot, 1,0,1,1)
self.gridLayout.addWidget(self.btn_line, 2,0,1,1)
self.btn_plot.clicked.connect(self.btnPlot)
self.btn_line.clicked.connect(self.btnLine)
def btnPlot(self):
self.checked = self.btn_plot.isChecked()
self.Graphics = Graphics('plot', self.checked, self.axes)
def btnLine(self):
self.checked = self.btn_line.isChecked()
self.Graphics = Graphics('line', self.checked, self.axes)
class Graphics:
def __init__(self, typeGraph, checked, axes):
self.typeGraph = typeGraph
self.checked = checked
self.axes = axes
if self.typeGraph == 'plot': self.drawPlot()
if self.typeGraph == 'line': self.drawLine()
def drawPlot(self):
if self.checked == True:
self.plot = self.axes.plot([10,20,30], [5,10,2], 'o')
else:
self.plot.remove()
self.axes.figure.canvas.draw()
def drawLine(self):
if self.checked == True:
self.vline1 = self.axes.axvline(x=15, linestyle="dashed", color="#595959")
self.vline2 = self.axes.axvline(x=25, linestyle="dashed", color="#595959")
else:
self.vline1.remove()
self.vline2.remove()
self.axes.figure.canvas.draw()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
prog = Mainwindow()
prog.show()
sys.exit(app.exec_())
Problem is be because when you click it then it creates always new Graphics (in btnPlot/btnLine) which doesn't have previous values - plot, vline1, vline2. You have to create Graphics only once and later run only drawPlot(checked), drawLine(checked) to add or remove item.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.pyplot import Figure
class Mainwindow(QMainWindow):
def __init__(self, parent=None):
super(Mainwindow, self).__init__(parent)
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
self.canvas = FigureCanvas(self.fig)
self.gridLayout = QGridLayout(centralWidget)
self.gridLayout.addWidget(self.canvas)
self.btn_plot = QCheckBox("Plot")
self.btn_line = QCheckBox("Line")
self.gridLayout.addWidget(self.btn_plot, 1,0,1,1)
self.gridLayout.addWidget(self.btn_line, 2,0,1,1)
self.btn_plot.clicked.connect(self.btnPlot)
self.btn_line.clicked.connect(self.btnLine)
# create only once
self.Graphics = Graphics(self.axes)
def btnPlot(self):
# add or remove
self.Graphics.drawPlot(self.btn_plot.isChecked())
def btnLine(self):
# add or remove
self.Graphics.drawLine(self.btn_line.isChecked())
class Graphics:
def __init__(self, axes):
self.axes = axes
# create at start with default values (but frankly, now I don't need it)
self.plot = None
self.vline1 = None
self.vline2 = None
def drawPlot(self, checked):
if checked:
self.plot = self.axes.plot([10,20,30], [5,10,2], 'o')
else:
for item in self.plot:
item.remove()
self.axes.figure.canvas.draw()
def drawLine(self, checked):
if checked:
self.vline1 = self.axes.axvline(x=15, linestyle="dashed", color="#595959")
self.vline2 = self.axes.axvline(x=25, linestyle="dashed", color="#595959")
else:
self.vline1.remove()
self.vline2.remove()
self.axes.figure.canvas.draw()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
prog = Mainwindow()
prog.show()
sys.exit(app.exec())
Related
I'm trying to make an app where the matplotlib's tab widget is embedded inside another widget
import os
import matplotlib
import matplotlib.pyplot as pp
import numpy as np
from PySide2 import QtGui
from PySide2.QtCore import QTimer
from PySide2.QtWidgets import *
from layout import Ui_Form
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import sys
graphed = False
res = 180
class VentanaPrincipal(QDialog):
def __init__(self, parent=None):
super(VentanaPrincipal, self).__init__(parent)
self.ventana = Ui_Form()
self.ventana.setupUi(self)
self.timer = QTimer()
self.timer.timeout.connect(self.mainloop)
self.timer.start(20)
self.ancho = self.size().height()
self.alto = self.size().height()
self.ventana.pshBtnCalcularOrbita.clicked.connect(self.truer)
self.ventana.pshBtnCalcularOrbita.clicked.connect(self.graph)
self.oldsize = self.size()
self.figure = Figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
self.button = QPushButton('Plot')
self.button.clicked.connect(self.plot)
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
self.setLayout(layout)
def truer(self):
global graphed
graphed = True
def graph(self):
self.ventana.graph()
def resizeEvent(self,event):
self.oldsize = event.size()
def mainloop(self):
self.ancho = self.size().width()
self.alto = self.size().height()
if self.size() != self.oldsize:
if graphed:
self.graph()
if __name__ == '__main__':
app = QApplication(sys.argv)
aplicacion = VentanaPrincipal()
aplicacion.show()
sys.exit(app.exec_())
Gives me:
TypeError: arguments did not match any overloaded call:
QToolBar(str, parent: QWidget = None): argument 1 has unexpected type 'VentanaPrincipal'
QToolBar(parent: QWidget = None): argument 1 has unexpected type 'VentanaPrincipal'
The Ui_Form is a .py file compiled from the original .ui file from QtDesigner
I've seen an identical example onto another question, the example i grabbed onto was:
import sys
from PySide2.QtWidgets import QDialog,QApplication,QPushButton, QVBoxLayout
from PySide2 import QtGui
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import random
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = Figure()
print(self)
# 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)
print(type(self))
# Just some button connected to `plot` method
self.button = QPushButton('Plot')
self.button.clicked.connect(self.plot)
# set the layout
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
self.setLayout(layout)
def plot(self):
''' plot some random stuff '''
# random data
data = [random.random() for i in range(10)]
# create an axis
ax = self.figure.add_subplot(111)
# discards the old graph
ax.clear()
# plot data
ax.plot(data, '*-')
# refresh canvas
self.canvas.draw()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
There are some prints i put inside the code to check which kind of object is accepted by the QToolbar init line inside Matplotlib's backend
I want to add a second animated graph to the GUI holding my first animated graph with both graphs animating at the same time, but I'm not sure how.
Here is my code :
import sys
import numpy as np
from matplotlib.backends.qt_compat import QtWidgets
from matplotlib.backends.backend_qt5agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
from matplotlib import animation
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
self.fig = Figure(figsize=(5, 3))
self.canvas = FigureCanvas(self.fig)
layout.addWidget(self.canvas)
self.addToolBar(NavigationToolbar(self.canvas, self))
self.setup()
def setup(self):
self.ax = self.fig.subplots()
self.ax.set_aspect('equal')
self.ax.grid(True, linestyle = '-', color = '0.10')
self.ax.set_xlim([-15, 15])
self.ax.set_ylim([-15, 15])
self.scat = self.ax.scatter([], [], c=(0.9, 0.1, 0.5), zorder=3)
self.scat.set_alpha(0.8)
self.anim = animation.FuncAnimation(self.fig, self.update,
frames = 720, interval = 10)
def update(self, i):
self.scat.set_offsets(([np.cos(np.radians(i))*7.5, np.sin(np.radians(i))*7.5], [0,0]))
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()
And here is some sample code which has two graphs inside the same window (like how I want to)
Here they use an _update_canvas function for the animated graph and the other graph (which is just a static graph) they plot it in the application window class.
I'm using an update plot function to animate my graph, do I need a second update plot function? How?
Sample code:
import sys
import time
import numpy as np
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
if is_pyqt5():
from matplotlib.backends.backend_qt5agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
else:
from matplotlib.backends.backend_qt4agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
static_canvas = FigureCanvas(Figure(figsize=(5, 3)))
layout.addWidget(static_canvas)
self.addToolBar(NavigationToolbar(static_canvas, self))
dynamic_canvas = FigureCanvas(Figure(figsize=(5, 3)))
layout.addWidget(dynamic_canvas)
self.addToolBar(QtCore.Qt.BottomToolBarArea,
NavigationToolbar(dynamic_canvas, self))
self._static_ax = static_canvas.figure.subplots()
t = np.linspace(0, 10, 501)
self._static_ax.plot(t, np.tan(t), ".")
self._dynamic_ax = dynamic_canvas.figure.subplots()
self._timer = dynamic_canvas.new_timer(
100, [(self._update_canvas, (), {})])
self._timer.start()
def _update_canvas(self):
self._dynamic_ax.clear()
t = np.linspace(0, 10, 101)
# Shift the sinusoid as a function of time.
self._dynamic_ax.plot(t, np.sin(t + time.time()))
self._dynamic_ax.figure.canvas.draw()
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()
To embed multiple animated graphs, you need to create multiple plot objects(Figure and FigureCanvas) then add each object to the QVBoxLayout. If you wanted to display it horizontally, you can use a QHBoxLayout. Each plot object will have its own subplot, grid, and data. To update each plot's data, you will need each plot to have its individual plot update function where you can pass this to the animation.FuncAnimation handler. So in your case, to have two animated graphs, you will need two update plot functions.
from matplotlib.figure import Figure
from matplotlib import animation
import numpy as np
import sys, matplotlib
from PyQt5 import QtWidgets, QtCore
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
# Configure figure 1
self.fig1 = Figure(figsize=(5, 3))
self.canvas1 = FigureCanvas(self.fig1)
# Configure figure 2
self.fig2 = Figure(figsize=(5, 3))
self.canvas2 = FigureCanvas(self.fig2)
layout.addWidget(self.canvas1)
layout.addWidget(self.canvas2)
self.addToolBar(NavigationToolbar(self.canvas1, self))
self.addToolBar(QtCore.Qt.BottomToolBarArea, NavigationToolbar(self.canvas2, self))
self.setup()
def setup(self):
# Plot 1 (top)
self.ax1 = self.fig1.subplots()
self.ax1.set_aspect('equal')
self.ax1.grid(True, linestyle = '-', color = '0.10')
self.ax1.set_xlim([-15, 15])
self.ax1.set_ylim([-15, 15])
# Plot 2 (bottom)
self.ax2 = self.fig2.subplots()
self.ax2.set_aspect('equal')
self.ax2.grid(True, linestyle = '-', color = '0.10')
self.ax2.set_xlim([-15, 15])
self.ax2.set_ylim([-15, 15])
self.scat1 = self.ax1.scatter([], [], c=(0.9, 0.1, 0.5), zorder=3)
self.scat1.set_alpha(0.8)
self.scat2 = self.ax2.scatter([], [], c=(0.9, 0.1, 0.5), zorder=3)
self.scat2.set_alpha(0.8)
self.anim1 = animation.FuncAnimation(self.fig1, self.update1,frames = 720, interval = 10)
self.anim2 = animation.FuncAnimation(self.fig2, self.update2,frames = 720, interval = 10)
# Update data for plot 1
def update1(self, i):
self.scat1.set_offsets(([np.cos(np.radians(i))*7.5, np.sin(np.radians(i))*7.5], [0,0]))
# Update data for plot 2
def update2(self, i):
self.scat2.set_offsets(([np.cos(np.radians(i))*7.5, np.sin(np.radians(i))*7.5], [0,0]))
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()
Is there a specific reason you need two separate canvas and two separate figures? If not, then I agree with ImportanceOfBeingErnest's comment and that you should create only one figure/canvas with 2 subplots, and call a single update function that takes care of updating the content of both axes.
In essence, your question would be a duplicate of this one, except for the fact that you are embedding the animation in a Qt app.
import sys
import time
import numpy as np
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
if is_pyqt5():
from matplotlib.backends.backend_qt5agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
else:
from matplotlib.backends.backend_qt4agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self._main = QtWidgets.QWidget()
self.setCentralWidget(self._main)
layout = QtWidgets.QVBoxLayout(self._main)
self.fig = Figure(figsize=(5, 6))
self.canvas = FigureCanvas(self.fig)
layout.addWidget(self.canvas)
self.addToolBar(QtCore.Qt.BottomToolBarArea,
NavigationToolbar(self.canvas, self))
self._axs = self.fig.subplots(2, 1)
self._timer = self.canvas.new_timer(
100, [(self._update_canvas, (), {})])
self._timer.start()
def _update_canvas(self):
[ax.clear() for ax in self._axs]
t = np.linspace(0, 10, 501)
self._axs[0].plot(t, np.tan(t + time.time()), ".")
t = np.linspace(0, 10, 101)
self._axs[1].plot(t, np.sin(t + time.time()))
self.canvas.draw()
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = ApplicationWindow()
app.show()
qapp.exec_()
I'm trying to update a matplotlib plot embeded in a pyqt5 window.
I used self.canvas.draw() (in the update function)to update the plot in a function to redraw the figure. This is working fine on Window but it doesn't work on MacOS.
I don't understand why and if it exists a solution to that?
In fact I need to click on the axes in order to the figure to be updated... weird.
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import numpy as np
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
class StimEdit(QMainWindow):
def __init__(self, parent=None):
super(StimEdit, self).__init__()
self.parent = parent
self.centralWidget = QWidget()
self.color = self.centralWidget.palette().color(QPalette.Background)
self.setCentralWidget(self.centralWidget)
self.mainHBOX_param_scene = QHBoxLayout()
self.set_Stims()
self.mainHBOX_param_scene.addWidget(self.Stimulation)
self.centralWidget.setLayout(self.mainHBOX_param_scene)
def set_Stims(self):
self.Stimulation = QGroupBox('Stim N°1')
self.layout_Stimulation_courbe = QVBoxLayout()
self.layout_Stimulation = QHBoxLayout()
self.button = QPushButton('push')
self.masceneparam = paramViewer(self)
self.button.clicked.connect(self.button_fun)
self.layout_Stimulation_courbe.addWidget(self.masceneparam)
self.layout_Stimulation_courbe.addWidget(self.button)
self.Stimulation.setLayout(self.layout_Stimulation_courbe)
def button_fun(self):
self.masceneparam.update()
self.parent.processEvents()
class paramViewer(QGraphicsView):
def __init__(self, parent=None):
super(paramViewer, self).__init__(parent)
self.parent=parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
self.axes_stim=self.figure.add_subplot(111)
self.canvas.setGeometry(0, 0, 1600, 500 )
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
self.setLayout(layout)
self.canvas.show()
def update(self):
self.axes_stim.clear()
t = np.arange(1000)/100
self.axes_stim.plot(t,np.sin(2*np.pi*np.random.uniform()*100*t))
self.canvas.draw()
def main():
app = QApplication(sys.argv)
ex = StimEdit(app)
ex.setWindowTitle('St ')
ex.show()
sys.exit(app.exec_( ))
if __name__ == '__main__':
main()
edit
I try to use the example of matplotlib for embeded Figures in Qt (https://matplotlib.org/gallery/user_interfaces/embedding_in_qt_sgskip.html) from #ImportanceOfBeingErnest
# from PyQt5.QtGui import *
# from PyQt5.QtWidgets import *
import numpy as np
import sys
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
if is_pyqt5():
from matplotlib.backends.backend_qt5agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
else:
from matplotlib.backends.backend_qt4agg import (
FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
class StimEdit(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(StimEdit, self).__init__()
self.parent = parent
self.centralWidget = QtWidgets.QWidget()
self.setCentralWidget(self.centralWidget)
self.mainHBOX_param_scene = QtWidgets.QHBoxLayout()
self.set_Stims()
self.mainHBOX_param_scene.addWidget(self.Stimulation)
self.centralWidget.setLayout(self.mainHBOX_param_scene)
def set_Stims(self):
self.Stimulation = QtWidgets.QGroupBox('Stim N°1')
self.layout_Stimulation_courbe = QtWidgets.QVBoxLayout()
self.layout_Stimulation = QtWidgets.QHBoxLayout()
self.button = QtWidgets.QPushButton('push')
self.masceneparam = paramViewer(self)
self.button.clicked.connect(self.button_fun)
self.layout_Stimulation_courbe.addWidget(self.masceneparam)
self.layout_Stimulation_courbe.addWidget(self.button)
self.Stimulation.setLayout(self.layout_Stimulation_courbe)
def button_fun(self):
self.masceneparam.update()
self.parent.processEvents()
class paramViewer(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(paramViewer, self).__init__(parent)
self.parent=parent
self.scene = QtWidgets.QGraphicsScene(self)
self.setScene(self.scene)
self.figure = Figure()
self.canvas = FigureCanvas(self.figure )
self.toolbar = NavigationToolbar(self.canvas, self)
self.axes_stim=self.figure.add_subplot(111)
self.canvas.setGeometry(0, 0, 1600, 500 )
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
self.setLayout(layout)
self.canvas.show()
def update(self):
self.axes_stim.clear()
t = np.arange(1000)/100
self.axes_stim.plot(t,np.sin(2*np.pi*np.random.uniform()*100*t))
self.canvas.figure.canvas.draw()
# self.canvas.draw()
def main():
app = QtWidgets.QApplication(sys.argv)
ex = StimEdit(app)
ex.setWindowTitle('St ')
ex.show()
sys.exit(app.exec_( ))
if __name__ == '__main__':
main()
But the issue still remains.
Answer from #ImportanceOfBeingErnest
Since I don't have any experience with Macs I might not be able to help further here, but a last suggestion might be to replace .draw() by .draw_idle(). (Both should work in this case, but you never know...)
I write a code to put an imshow in a pyqt environment but the imshow is not centered in the figure:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import numpy as np
import sys
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
class GenerateCM(QMainWindow):
def __init__(self, parent=None):
super(GenerateCM, self).__init__()
self.CM = np.zeros((10,10))
#######################################
self.centralWidget = QWidget()
self.setCentralWidget(self.centralWidget)
self.mainHBOX_param_scene = QHBoxLayout()
#CM view
layout_plot = QHBoxLayout()
self.loaded_plot = CMViewer(self)
self.loaded_plot.setMinimumHeight(200)
self.loaded_plot.update()
layout_plot.addWidget(self.loaded_plot)
self.mainHBOX_param_scene.addLayout(layout_plot)
self.centralWidget.setLayout(self.mainHBOX_param_scene)
class CMViewer(QGraphicsView):
def __init__(self, parent=None):
super(CMViewer, self).__init__(parent)
self.parent=parent
self.scene = QGraphicsScene(self)
self.setScene(self.scene)
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
# self.canvas.setGeometry(0, 0, 1600, 500 )
layout = QVBoxLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
self.setLayout(layout)
self.canvas.show()
def update(self):
self.connectivityMat = self.parent.CM
self.figure.clear()
self.axes=self.figure.add_subplot(1,1,1)
im = self.axes.imshow(self.connectivityMat)
self.figure.colorbar(im)
self.axes.axis('off')
self.axes.set_title('Loaded Matrix')
self.canvas.draw()
self.canvas.show()
def main():
app = QApplication(sys.argv)
ex = GenerateCM(app )
ex.show()
sys.exit(app.exec_( ))
if __name__ == '__main__':
main()
Which give me this result.
I would like the image to be in the center of the window and not shifted to the rigth as it is for now. I thing I did something wrong with adding a subplot but I cannot find the right way to correctly put the subplot right in the center
I'm designing a GUI with PyQt where I need to display a matplotlib/pylab window when I click on a button that makes the plot of the data from a function I've created. It's like a runtime used in Matlab. I want to keep the matplotlib/pylab window as my window everytime I press that button.
Here is a basic example that will plot three different samples using a QThread:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import random
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from PyQt4 import QtGui, QtCore
class MatplotlibWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(parent)
self.figure = Figure()
self.canvas = FigureCanvasQTAgg(self.figure)
self.axis = self.figure.add_subplot(111)
self.layoutVertical = QtGui.QVBoxLayout(self)
self.layoutVertical.addWidget(self.canvas)
class ThreadSample(QtCore.QThread):
newSample = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(ThreadSample, self).__init__(parent)
def run(self):
randomSample = random.sample(range(0, 10), 10)
self.newSample.emit(randomSample)
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonPlot = QtGui.QPushButton(self)
self.pushButtonPlot.setText("Plot")
self.pushButtonPlot.clicked.connect(self.on_pushButtonPlot_clicked)
self.matplotlibWidget = MatplotlibWidget(self)
self.layoutVertical = QtGui.QVBoxLayout(self)
self.layoutVertical.addWidget(self.pushButtonPlot)
self.layoutVertical.addWidget(self.matplotlibWidget)
self.threadSample = ThreadSample(self)
self.threadSample.newSample.connect(self.on_threadSample_newSample)
self.threadSample.finished.connect(self.on_threadSample_finished)
#QtCore.pyqtSlot()
def on_pushButtonPlot_clicked(self):
self.samples = 0
self.matplotlibWidget.axis.clear()
self.threadSample.start()
#QtCore.pyqtSlot(list)
def on_threadSample_newSample(self, sample):
self.matplotlibWidget.axis.plot(sample)
self.matplotlibWidget.canvas.draw()
#QtCore.pyqtSlot()
def on_threadSample_finished(self):
self.samples += 1
if self.samples <= 2:
self.threadSample.start()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.resize(666, 333)
main.show()
sys.exit(app.exec_())
This is code from user1006989 (best answer) adapted to PyQt5, hopefully it will be useful to someone:
Here is a basic example that will plot three different samples using a QThread:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import random
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from PyQt5 import QtCore #conda install pyqt
from PyQt5 import QtWidgets
class MatplotlibWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(parent)
self.figure = Figure()
self.canvas = FigureCanvasQTAgg(self.figure)
self.axis = self.figure.add_subplot(111)
self.layoutVertical = QtWidgets.QVBoxLayout(self)#QVBoxLayout
self.layoutVertical.addWidget(self.canvas)
class ThreadSample(QtCore.QThread):
newSample = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(ThreadSample, self).__init__(parent)
def run(self):
randomSample = random.sample(range(0, 10), 10)
self.newSample.emit(randomSample)
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonPlot = QtWidgets.QPushButton(self)
self.pushButtonPlot.setText("Plot")
self.pushButtonPlot.clicked.connect(self.on_pushButtonPlot_clicked)
self.matplotlibWidget = MatplotlibWidget(self)
self.layoutVertical = QtWidgets.QVBoxLayout(self)
self.layoutVertical.addWidget(self.pushButtonPlot)
self.layoutVertical.addWidget(self.matplotlibWidget)
self.threadSample = ThreadSample(self)
self.threadSample.newSample.connect(self.on_threadSample_newSample)
self.threadSample.finished.connect(self.on_threadSample_finished)
#QtCore.pyqtSlot()
def on_pushButtonPlot_clicked(self):
self.samples = 0
self.matplotlibWidget.axis.clear()
self.threadSample.start()
#QtCore.pyqtSlot(list)
def on_threadSample_newSample(self, sample):
self.matplotlibWidget.axis.plot(sample)
self.matplotlibWidget.canvas.draw()
#QtCore.pyqtSlot()
def on_threadSample_finished(self):
self.samples += 1
if self.samples <= 2:
self.threadSample.start()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.resize(666, 333)
main.show()
sys.exit(app.exec_())
Eli Bendersky has written a code example that uses matplotlib within PyQt: http://eli.thegreenplace.net/2009/01/20/matplotlib-with-pyqt-guis/
Integrating Matplotlib with PyQt takes a little work. Here's an example:
http://sourceforge.net/mailarchive/message.php?msg_id=29086544
However, there are a few plotting libraries designed specifically around PyQt:
pyqwt (edit: no longer maintained)
guiqwt
pyqtgraph
If I understand you correctly you have an application with a GUI and you want to plot a graph in a separate window than the GUI uses. pyqtgraph can do this nicely.
first type pip install pyqtgraph in the command prompt to install pyqtgraph
then
import pyqtgraph as pg
pg.setConfigOption('background', 'w') # sets background to white
pg.setConfigOption('foreground', 'k') # sets axis color to black
pw = pg.plot(x, y, pen='g') # 1st plot (green)
pw.plot(x2, y2, pen='b') # 2nd plot in same figure (blue)
pw.setLabel('bottom', 'x-label') # x-label
pw.setLabel('left', 'y-label') # y-label
more info here:
http://www.pyqtgraph.org/documentation/how_to_use.html