I am working on GUI where I have tab system with graphs. I want that if a user clicks (or puts cursor) at any point in the graph, it shows the exact x and y values in that point like that:
I know that in usual matplotlib it is easy to implement; however I do not know how to do that in PyQt5.
My tabs system and canvas look like that:
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QApplication, QWidget,QVBoxLayout,QTabWidget
import sys
import matplotlib.pyplot as plt
def mouse_move(event):
x, y = event.xdata, event.ydata
print(x, y)
plt.connect('motion_notify_event', mouse_move)
class Canvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi=80):
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):
x = ['22-02 11:16:15', '22-02 15:31:54', '22-02 15:32:30',
'22-02 15:32:45', '22-02 15:33:57', '22-02 15:34:13',
'22-02 15:34:46']
y = [1, 4, 3, 4, 8, 9, 2]
self.figure.tight_layout()
ax = self.figure.add_subplot(111)
ax.plot(x, y)
class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.top = 255
self.left = 150
self.setGeometry(self.left, self.top, 900, 900)
self.Mainlayout = QVBoxLayout(self)
self.tabs = QTabWidget()
self.graphUP = QWidget()
self.graphUP.layout = QVBoxLayout( self.graphUP)
self.graphUP.layout.addWidget(Canvas())
self.tabs.setFixedHeight(800)
self.tabs.setFixedWidth(800)
self.tabs.addTab(self.graphUP, "Graph1")
self.Mainlayout.addWidget(self.tabs)
self.show()
if __name__ == '__main__':
App = QApplication(sys.argv)
window = MainWindow()
sys.exit(App.exec())
import this module:
import mplcursors as mpl
and add : mpl.cursor(hover=True)
in your def plot() function.
Related
I am trying to embed a Matplotlib Plot in a PyQt5 Window. I am using the following code:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton
import sys
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
class Window(QMainWindow):
def __init__(self):
super().__init__()
title ='Matplotlib Embedding In PyQt5'
top= 400
left = top
width = 900
height = 500
self.setWindowTitle(title)
self.setGeometry(left, top, width, height)
self.ui()
def ui(self):
canvas1 = Canvas(self, width=4, height=4)
button = QPushButton('Click me', self)
button.move(250, 450)
self.plot(canvas1)
def plot(self, canvas):
x= np.linspace(0, 1, 200)
y = np.sinc(x)
ax = canvas.figure.add_subplot(111)
ax.plot(x,y)
class Canvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi = 100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
app = QtWidgets.QApplication(sys.argv)
main_window = Window()
main_window.show()
sys.exit(app.exec())
However, when I run that (using Python 3.8.10), I get:
As you can see, there is something wrong with the axes labels.
How can I fix that?
You are creating 2 axes:
self.axes = fig.add_subplot(111)
ax = canvas.figure.add_subplot(111)
The solution is to reuse the existing axes:
def plot(self, canvas):
x = np.linspace(0, 1, 200)
y = np.sinc(x)
canvas.axes.plot(x, y)
Or clean the figure before:
def plot(self, canvas):
x = np.linspace(0, 1, 200)
y = np.sinc(x)
canvas.figure.clear()
ax = canvas.figure.add_subplot(111)
ax.plot(x, y)
I have a PyQt5 GUI application. This application shows a graph (with my default xlim and ylim) that gets updated every second, a real-time graph basically. This functionality I have, but I want to add a NavigationToolbar so one can zoom in/out the graph.
I added the toolbar to my layout and it gets displayed. So far so good. Now I zoom in, the graph gets zoomed in, but once the graph gets periodically updated the xlim and ylim are defaulted again and the zoom is gone. What properties I need to call from the toolbar so I can save them and pass them to my _update_canvas function? I looked at https://matplotlib.org/3.1.0/api/axes_api.html, and noticed the function get_ylim. So i tried as followed:
self._dynamic_ax.set_ylim(self._dynamic_ax.get_ylim()) and self._dynamic_ax.set_ylim(self._dynamic_ax2.get_ylim())
As well as:
self._dynamic_ax.set_navigate(True)
However these didn't work. How can I persist the settings set by NavigationToolbar? Not only the zoom but also the pan.
A minimal runnable code sample:
import sys
from matplotlib.backends.qt_compat import QtCore, QtWidgets, QtGui
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
buffer_size = 120
t = [t for t in range(buffer_size)]
bitthrough = [t for t in range(buffer_size)]
errors = bitthrough[::-1]
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PCANbus sniffer")
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.setMinimumSize(QtCore.QSize(640, 400))
self.show()
class MyTableWidget(QtWidgets.QWidget):
def __init__(self, parent):
super(QtWidgets.QWidget, self).__init__(parent)
self.layout = QtWidgets.QVBoxLayout(self)
self.tabs = QtWidgets.QTabWidget()
self.tab_graph = QtWidgets.QWidget()
self.tab_info = QtWidgets.QWidget()
self.tabs.addTab(self.tab_graph, "PCANbus occupation")
self.tabs.addTab(self.tab_info, "PCANbus information")
self.tab_graph.layout = QtWidgets.QVBoxLayout(self)
self.dynamic_canvas = FigureCanvas(Figure(figsize=(6, 4)))
self.tab_graph.layout.addWidget(self.dynamic_canvas)
self.toolbar = NavigationToolbar(self.dynamic_canvas, self)
self.tab_graph.layout.addWidget(self.toolbar)
self._dynamic_ax = self.dynamic_canvas.figure.subplots()
self._dynamic_ax.set_xlabel("time (s)")
self._dynamic_ax.set_xlim(-5, 125)
self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
self._dynamic_ax.set_ylim(-5, 120)
self._dynamic_ax.tick_params(axis="y", labelcolor="black")
# self._dynamic_ax.set_navigate(True)
self._dynamic_ax2 = self._dynamic_ax.twinx()
self._dynamic_ax2.set_ylabel("Errors (%)", color="blue")
self._dynamic_ax2.set_ylim(-4, 100)
self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")
#self._dynamic_ax2.set_navigate(True)
self.tab_graph.setLayout(self.tab_graph.layout)
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self._update_canvas)
self.timer.start(1000)
def _update_canvas(self):
self._dynamic_ax.clear()
self._dynamic_ax.plot(t, bitthrough, color="black")
self._dynamic_ax.set_xlabel("time (s)")
self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
self._dynamic_ax.set_ylim(-5, 120) #self._dynamic_ax.get_ylim())
self._dynamic_ax.tick_params(axis="y", labelcolor="black")
self._dynamic_ax2.clear()
self._dynamic_ax2.plot(t, errors, color="blue")
self._dynamic_ax2.set_ylabel("Errors", color="blue")
self._dynamic_ax2.set_ylim(-4, 100) #self._dynamic_ax2.get_ylim())
self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")
self._dynamic_ax.figure.canvas.draw_idle()
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = App()
app.show()
qapp.exec_()
My real _update_canvas function:
def _update_canvas(self):
wh_green = [a <= b for a, b in zip(bitthrough, llvl)]
wh_orange = [a > b and a <= c
for a, b, c in zip(bitthrough, llvl, lvl)]
wh_red = [a > b for a, b, in zip(bitthrough, lvl)]
# self._dynamic_ax.clear()
# self._dynamic_ax2.clear()
self._dynamic_ax.fill_between(
t, 0, bitthrough, where=wh_red, color="red", interpolate=True
)
self._dynamic_ax.fill_between(
t, 0, bitthrough, where=wh_orange, color="orange", interpolate=True
)
self._dynamic_ax.fill_between(
t, 0, bitthrough, where=wh_green, color="green", interpolate=True
)
# self._dynamic_ax.plot(t, bitthrough, color="black")
# self._dynamic_ax.set_xlabel("time (s)")
# self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
# #self._dynamic_ax.set_ylim(self._dynamic_ax.get_ylim())
# self._dynamic_ax.tick_params(axis="y", labelcolor="black")
# self._dynamic_ax2.plot(t, errors, color="blue")
# self._dynamic_ax2.set_ylabel("Errors", color="blue")
# #self._dynamic_ax2.set_ylim(self._dynamic_ax2.get_ylim())
# self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")
self._plot1.set_ydata(bitthrough)
self._plot2.set_ydata(errors)
# logging.debug("redrawing graph!!")
self._dynamic_ax.figure.canvas.draw_idle()
The solution of #DizietAsahi doesn't work while using fill_between. The area gets overwritten and not cleared. So they are displayed on top of eachother.
My advice would be to not clear the figure at each update. Instead, store a reference to the Line2D artists created by plot() and update the {x|y}data (using set_data() or set_ydata()) in your update function.
import sys
from matplotlib.backends.qt_compat import QtCore, QtWidgets, QtGui
from matplotlib.backends.backend_qt5agg import (FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
buffer_size = 120
t = np.linspace(0, 100, buffer_size)
bitthrough = 120*np.random.random(size=(buffer_size,))
errors = bitthrough[::-1]
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PCANbus sniffer")
self.table_widget = MyTableWidget(self)
self.setCentralWidget(self.table_widget)
self.setMinimumSize(QtCore.QSize(640, 400))
self.show()
class MyTableWidget(QtWidgets.QWidget):
def __init__(self, parent):
super(QtWidgets.QWidget, self).__init__(parent)
self.layout = QtWidgets.QVBoxLayout(self)
self.tabs = QtWidgets.QTabWidget()
self.tab_graph = QtWidgets.QWidget()
self.tab_info = QtWidgets.QWidget()
self.tabs.addTab(self.tab_graph, "PCANbus occupation")
self.tabs.addTab(self.tab_info, "PCANbus information")
self.tab_graph.layout = QtWidgets.QVBoxLayout(self)
self.dynamic_canvas = FigureCanvas(Figure(figsize=(6, 4)))
self.tab_graph.layout.addWidget(self.dynamic_canvas)
self.toolbar = NavigationToolbar(self.dynamic_canvas, self)
self.tab_graph.layout.addWidget(self.toolbar)
self._dynamic_ax = self.dynamic_canvas.figure.subplots()
self._dynamic_ax.set_xlabel("time (s)")
self._dynamic_ax.set_xlim(-5, 125)
self._dynamic_ax.set_ylabel("Throughput (%)", color="black")
self._dynamic_ax.set_ylim(-5, 120)
self._dynamic_ax.tick_params(axis="y", labelcolor="black")
# self._dynamic_ax.set_navigate(True)
self._dynamic_ax2 = self._dynamic_ax.twinx()
self._dynamic_ax2.set_ylabel("Errors (%)", color="blue")
self._dynamic_ax2.set_ylim(-4, 100)
self._dynamic_ax2.tick_params(axis="y", labelcolor="blue")
#self._dynamic_ax2.set_navigate(True)
##
## Create plots here (initially empty)
##
self._plot1, = self._dynamic_ax.plot(t, np.empty(shape=(buffer_size,)), color="black")
self._plot2, = self._dynamic_ax2.plot(t, np.empty(shape=(buffer_size,)), color="blue")
self._fill1 = self._dynamic_ax.fill_between(t, 0, bitthrough, color="orange")
self.tab_graph.setLayout(self.tab_graph.layout)
self.layout.addWidget(self.tabs)
self.setLayout(self.layout)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self._update_canvas)
self.timer.start(1000)
def _update_canvas(self):
bitthrough = 120*np.random.random(size=(buffer_size, ))
errors = bitthrough[::-1]
##
## update the content of the plots here, without clearing the figure
##
self._plot1.set_ydata(bitthrough)
self._plot2.set_ydata(errors)
self._fill1.remove()
self._fill1 = self._dynamic_ax.fill_between(t, 0, bitthrough, color="orange")
self._dynamic_ax.figure.canvas.draw_idle()
if __name__ == "__main__":
qapp = QtWidgets.QApplication(sys.argv)
app = App()
app.show()
qapp.exec_()
EDIT
I've added some code for handling fill_between().
fill_between() returns a PolyCollection which is a pain to update, so the best option there is to remove the PolyCollection and re-create it at each update (but not clear the whole figure).
I am new to Qt and I am trying to do a program, that I've previously done in tkinter, to learn how to use it. I have embedded a FigureCanvasQtAgg in a Qt window. I have ploted thing on it. Now I want to plot on this canvas a circle on user's mouse click.
What I have done to do it on Tkinter is to use :
self.canvas.get_tk_widget().create_oval()
Is there a simple way to have the same results in PySide2?
Here is a simpler code with what I've tried :
from PySide2.QtWidgets import *
from PySide2.QtCore import *
from PySide2.QtGui import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
import numpy as np
import sys
class MyPaintWidget(QWidget):
def __init__(self):
super().__init__()
layout_canvas = QVBoxLayout()
self.fig = plt.gcf()
plt.plot(np.cos([i for i in np.arange(0, 10, 0.1)]))
self.canvas = FigureCanvas(self.fig)
self.canvas.mpl_connect('button_press_event', self._on_left_click)
layout_canvas.addWidget(self.canvas)
self.setLayout(layout_canvas)
def _on_left_click(self, event):
print(event.xdata, event.ydata)
qp = QPainter()
qp.drawEllipse(QPointF(event.x, event.y), 10, 10)
qp.end()
self.canvas.draw()
if __name__=="__main__":
app = QApplication(sys.argv)
w = MyPaintWidget()
w.show()
app.exec_()
What I have done in tkinter (when I click on the canvas a green point does appear) :
import tkinter as tk
import tkinter.ttk as ttk
import numpy as np
import sys
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
import matplotlib.pyplot as plt
class MainFrame(ttk.Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master)
self.master = master
self.fig = plt.gcf()
plt.plot(np.cos([i for i in np.arange(0, 10, 0.1)]))
self.canvas = FigureCanvasTkAgg(self.fig, master=self.master) # A tk.DrawingArea.
self.canvas.get_tk_widget().grid(row=0, column=0)
self.canvas.draw()
self.canvas.mpl_connect('button_press_event', self._on_left_click)
def _on_left_click(self, event):
self._add_point(event.x, event.y)
def _add_point(self, x, y):
self.canvas.get_tk_widget().create_oval(x - 4, self.canvas.get_tk_widget().winfo_height() - (y - 4), x + 4,
self.canvas.get_tk_widget().winfo_height() - (y + 4), fill='green')
if __name__=="__main__":
window = tk.Tk()
main_frame = MainFrame(window)
window.mainloop()
Any ideas to get this result in QT ? Thanks !
Unlike tkinter Qt does not implement a function like create_oval() to make the circles so an alternative is to use the tools of matplotlib.
from PySide2 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
import numpy as np
class MyPaintWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.figure = plt.gcf()
self.canvas = FigureCanvas(self.figure)
self.canvas.mpl_connect("button_press_event", self._on_left_click)
self.axes = self.figure.add_subplot(111)
x = np.arange(0, 10, 0.1)
y = np.cos(x)
self.axes.plot(x, y)
layout_canvas = QtWidgets.QVBoxLayout(self)
layout_canvas.addWidget(self.canvas)
def _on_left_click(self, event):
self.axes.scatter(event.xdata, event.ydata)
self.figure.canvas.draw()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyPaintWidget()
w.show()
sys.exit(app.exec_())
Another possible solution is to implement the method create_oval() inheriting from the class FigureCanvas:
from PySide2 import QtCore, QtGui, QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import numpy as np
class PainterCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
FigureCanvas.__init__(self, fig)
self.setParent(parent)
self._instructions = []
self.axes = self.figure.add_subplot(111)
def paintEvent(self, event):
super().paintEvent(event)
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
width, height = self.get_width_height()
for x, y, rx, ry, br_color in self._instructions:
x_pixel, y_pixel_m = self.axes.transData.transform((x, y))
# In matplotlib, 0,0 is the lower left corner,
# whereas it's usually the upper right
# for most image software, so we'll flip the y-coor
y_pixel = height - y_pixel_m
painter.setBrush(QtGui.QColor(br_color))
painter.drawEllipse( QtCore.QPoint(x_pixel, y_pixel), rx, ry)
def create_oval(self, x, y, radius_x=5, radius_y=5, brush_color="red"):
self._instructions.append([x, y, radius_x, radius_y, brush_color])
self.update()
class MyPaintWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.canvas = PainterCanvas()
self.canvas.mpl_connect("button_press_event", self._on_left_click)
x = np.arange(0, 10, 0.1)
y = np.cos(x)
self.canvas.axes.plot(x, y)
layout_canvas = QtWidgets.QVBoxLayout(self)
layout_canvas.addWidget(self.canvas)
def _on_left_click(self, event):
self.canvas.create_oval(event.xdata, event.ydata, brush_color="green")
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MyPaintWidget()
w.show()
sys.exit(app.exec_())
I wrote the following code in python to show a bar chart in the GUI generated by PyQt5.
import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout, \
QLineEdit, QMessageBox, QInputDialog, QLabel, QHBoxLayout, QGridLayout, QStackedLayout, QFormLayout
from PyQt5 import QtCore, QtGui, QtWidgets
import time
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.lines import Line2D
import matplotlib.animation as animation
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
# data
import numpy as np
#import matplotlib.pyplot as plt
import pandas as pd
import os
import csv
#define the path to data
pathToData='C:/RC/python/data/'
dataName= '31122017ARB.csv'
# import
data=pd.read_csv(pathToData+dataName, delimiter=';',encoding='cp1252')
# percent MW
data['MWP']=data[' MW ']/sum(data[' MW '])
#aggregate by Best
datag=data.groupby('Best', as_index=False).agg({'MW': 'sum'})
x=["BE"+s for s in[str(s) for s in [int(x) for x in datag.iloc[:,0].tolist()]]]
y=datag.ix[:,1].tolist()
figure = plt.figure()
H = np.array([[100, 2, 39, 190], [402, 55, 369, 1023], [300, 700, 8, 412], [170, 530, 330, 1]])
Z = np.array([[3, 290, 600, 480], [1011, 230, 830, 0], [152, 750, 5, 919], [340, 7, 543, 812]])
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = plt.figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init_
self.im = None
self.canvas = FigureCanvas(self.figure)
self.canvas.mpl_connect('button_press_event', self.on_button_press_event)
# this is the Navigation widget
# it takes the Canvas widget and a parent
self.toolbar = NavigationToolbar(self.canvas, self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.plot)
self.timer.setInterval(5000)
# Just some button connected to `plot` method
self.button = QPushButton('Plot')
self.button.clicked.connect(self.timer.start)
self.button.setDefault(False)
self.stop = QPushButton("Stop")
self.stop.clicked.connect(self.timer.stop)
self.stop.setDefault(False)
self.exit = QPushButton('Exit')
self.exit.clicked.connect(self.close)
self.exit.setDefault(True)
layout = QFormLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
layout.addWidget(self.stop)
layout.addWidget(self.exit)
self.setLayout(layout)
self.lb = QtWidgets.QLabel(self)
self.lb.setWindowFlags(QtCore.Qt.ToolTip)
def plot(self):
self.x = ["BE"+s for s in[str(s) for s in [int(x) for x in datag.iloc[:,0].tolist()]]]
self.y = datag.iloc[:,1].tolist()#np.sin(self.x)
self.setWindowTitle("Bestandseingruppierung")
def update_figure(self):
self.axes.bar(self.x, self.y)
#self.y = np.roll(self.y,-1)
#self.draw()
self.canvas.draw()
def on_button_press_event(self, event):
print('button={}, x={}, y={}, xdata={}, ydata={}'
.format(event.button, event.x, event.y, event.xdata, event.ydata))
if self.im:
message = str(self.im.get_cursor_data(event))
delay = 1000
w = self.lb.fontMetrics().width(message)
self.lb.resize(w, self.lb.size().height())
self.lb.setText(message)
self.lb.move(QtGui.QCursor.pos())
self.lb.show()
QtCore.QTimer.singleShot(delay, self.lb.hide)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
The Problem is: it is not shown any plot, even I do not get any error. I just obtain an empty .
How can I get the chart by pressing the plot bottom? I guess, I am doing some thing wrong under def plot(self):.
Just because of clarification: I tested the chart within a GUI generated by PyQt5 as a stand alone code, which works totally fine:
# FigureCanvas inherits QWidget
class MainWindow(FigureCanvas):
def __init__(self, parent=None, width=4, height=3, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
self.axes.hold(False)
super(MainWindow, self).__init__(fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
timer = QTimer(self)
timer.timeout.connect(self.update_figure)
timer.start(50)
self.x = ["BE"+s for s in[str(s) for s in [int(x) for x in datag.iloc[:,0].tolist()]]]#np.arange(0, 4*np.pi, 0.1)
self.y = datag.iloc[:,1].tolist()#np.sin(self.x)
self.setWindowTitle("Best")
def update_figure(self):
self.axes.bar(self.x, self.y)
#self.y = np.roll(self.y,-1)
self.draw()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
I found the solution!
I have 3 botons in this GUI as shown in the following part of the code:
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = plt.figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init_
self.im = None
self.canvas = FigureCanvas(self.figure)
self.canvas.mpl_connect('button_press_event', self.on_button_press_event)
# this is the Navigation widget
# it takes the Canvas widget and a parent
self.toolbar = NavigationToolbar(self.canvas, self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.plot)
self.timer.setInterval(0)
# Just some button connected to `plot` method
self.button = QPushButton('Plot')
self.button.clicked.connect(self.timer.start)
self.button.setDefault(False)
self.stop = QPushButton("Stop")
self.stop.clicked.connect(self.timer.stop)
self.stop.setDefault(False)
self.exit = QPushButton('Exit')
self.exit.clicked.connect(self.close)
self.exit.setDefault(True)
One has to set the time delay in self.timer.setInterval(0) to Zero! That is the first point.
The part def plot(self) should be changed as follows:
def plot(self):
data=x
self.setWindowTitle("Bestandseingruppierung")
# instead of ax.hold(False)
self.figure.clear()
# create an axis
ax = self.figure.add_subplot(111)
#fig.autofmt_xdate()
# discards the old graph
ax.hold(False) # deprecated, see above
# plot data
ax.axes.bar(data,y)
self.canvas.draw()
everyone! I want to embed my data into Gui. Here I created 2 Plot button so that I showed my data one by one.Plot1 contained 2 subplot, Plot2 contained 1 plot.
But when I clicked Plot1 and then clicked Plot2, I can't see my data in Plot2, It looks like coordinate doesn't change. How should I fix this?
import matplotlib.pyplot as plt
import numpy as np
import sys
from PyQt4 import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
class PrettyWidget(QtGui.QWidget):
def __init__(self):
super(PrettyWidget, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(100,100,800,600)
self.center()
self.setWindowTitle('S Plot')
grid = QtGui.QGridLayout()
self.setLayout(grid)
btn1 = QtGui.QPushButton('Plot 1 ',self)
btn1.resize(btn1.sizeHint())
btn1.clicked.connect(self.plot1)
grid.addWidget(btn1,5,0)
btn2 = QtGui.QPushButton('Plot 2 ',self)
btn2.resize(btn2.sizeHint())
btn2.clicked.connect(self.plot2)
grid.addWidget(btn2,5,1)
self.figure = plt.figure(figsize = (15,5))
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
grid.addWidget(self.canvas, 3,0,1,2)
grid.addWidget(self.canvas, 3,0,1,2)
self.show()
def plot1(self):
plt.cla()
ax1 = self.figure.add_subplot(211)
x1 = [i for i in range(100)]
y1 = [i**0.5 for i in x1]
ax1.plot(x1,y1,'b.-')
ax2 = self.figure.add_subplot(212)
x2 = [i for i in range(100)]
y2 = [i for i in x2]
ax2.plot(x2,y2,'b.-')
self.canvas.draw()
def plot2(self):
plt.cla()
ax3 = self.figure.add_subplot(111)
x = [i for i in range(100)]
y = [i**0.5 for i in x]
ax3.plot(x,y,'r.-')
ax3.set_title('Square Root Plot')
self.canvas.draw()
def center(self):
qr = self.frameGeometry()
cp = QtGui.QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
app = QtGui.QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
GUI = PrettyWidget()
sys.exit(app.exec_())
I strongly advise against using pyplot whe doing embedding, the global state management and the FigureManager classes will get in your way.
import sys
from PyQt4 import QtGui
import matplotlib
import matplotlib.figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
class PrettyWidget(QtGui.QWidget):
def __init__(self):
super(PrettyWidget, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(100, 100, 800, 600)
self.center()
self.setWindowTitle('S Plot')
grid = QtGui.QGridLayout()
self.setLayout(grid)
btn1 = QtGui.QPushButton('Plot 1 ', self)
btn1.resize(btn1.sizeHint())
btn1.clicked.connect(self.plot1)
grid.addWidget(btn1, 5, 0)
btn2 = QtGui.QPushButton('Plot 2 ', self)
btn2.resize(btn2.sizeHint())
btn2.clicked.connect(self.plot2)
grid.addWidget(btn2, 5, 1)
self.figure = matplotlib.figure.Figure()
self.canvas = FigureCanvas(self.figure)
self.toolbar = NavigationToolbar(self.canvas, self)
grid.addWidget(self.canvas, 3, 0, 1, 2)
# grid.addWidget(self.toolbar, ??)
self.show()
def plot1(self):
self.figure.clf()
ax1 = self.figure.add_subplot(211)
x1 = [i for i in range(100)]
y1 = [i**0.5 for i in x1]
ax1.plot(x1, y1, 'b.-')
ax2 = self.figure.add_subplot(212)
x2 = [i for i in range(100)]
y2 = [i for i in x2]
ax2.plot(x2, y2, 'b.-')
self.canvas.draw_idle()
def plot2(self):
self.figure.clf()
ax3 = self.figure.add_subplot(111)
x = [i for i in range(100)]
y = [i**0.5 for i in x]
ax3.plot(x, y, 'r.-')
ax3.set_title('Square Root Plot')
self.canvas.draw_idle()
def center(self):
qr = self.frameGeometry()
cp = QtGui.QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
app = QtGui.QApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
GUI = PrettyWidget()
sys.exit(app.exec_())