利用PyQt5+Matplotlib 繪制靜態(tài)/動態(tài)圖的實現(xiàn)代碼
代碼編輯環(huán)境
Win10+(Pycharmm or Vscode)+PyQt 5.14.2
功能實現(xiàn)
靜態(tài)作圖:數(shù)據(jù)作圖,取決于作圖函數(shù),可自行修改
動態(tài)作圖:產(chǎn)生數(shù)據(jù),獲取并更新數(shù)據(jù),最后刷新顯示,可用于實現(xiàn)數(shù)據(jù)實時采集并顯示的場景
效果展示

代碼塊(業(yè)務(wù)與邏輯分離)業(yè)務(wù)–UI界面代碼
文件名:Ui_realtimer_plot.py
# -*- coding: utf-8 -*-
# Added by the Blog author VERtiCaL on 2020/07/12 at SSRF
# Created by: PyQt5 UI code generator 5.14.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1613, 1308)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.Plot_static = QtWidgets.QGroupBox(self.centralwidget)
self.Plot_static.setGeometry(QtCore.QRect(260, 30, 861, 391))
self.Plot_static.setObjectName("Plot_static")
self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
self.layoutWidget.setGeometry(QtCore.QRect(300, 830, 701, 91))
self.layoutWidget.setObjectName("layoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setSpacing(28)
self.horizontalLayout.setObjectName("horizontalLayout")
self.Static_plot = QtWidgets.QPushButton(self.layoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.Static_plot.sizePolicy().hasHeightForWidth())
self.Static_plot.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("楷體")
font.setPointSize(18)
font.setBold(False)
font.setWeight(50)
self.Static_plot.setFont(font)
self.Static_plot.setObjectName("Static_plot")
self.horizontalLayout.addWidget(self.Static_plot)
self.dynamic_plot = QtWidgets.QPushButton(self.layoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.dynamic_plot.sizePolicy().hasHeightForWidth())
self.dynamic_plot.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("楷體")
font.setPointSize(18)
font.setBold(False)
font.setWeight(50)
self.dynamic_plot.setFont(font)
self.dynamic_plot.setObjectName("dynamic_plot")
self.horizontalLayout.addWidget(self.dynamic_plot)
self.End_plot = QtWidgets.QPushButton(self.layoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.End_plot.sizePolicy().hasHeightForWidth())
self.End_plot.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("楷體")
font.setPointSize(18)
self.End_plot.setFont(font)
self.End_plot.setObjectName("End_plot")
self.horizontalLayout.addWidget(self.End_plot)
self.Erase_plot = QtWidgets.QPushButton(self.layoutWidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.Erase_plot.sizePolicy().hasHeightForWidth())
self.Erase_plot.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("楷體")
font.setPointSize(18)
self.Erase_plot.setFont(font)
self.Erase_plot.setObjectName("Erase_plot")
self.horizontalLayout.addWidget(self.Erase_plot)
self.Plot_dynamic = QtWidgets.QGroupBox(self.centralwidget)
self.Plot_dynamic.setGeometry(QtCore.QRect(260, 430, 861, 391))
self.Plot_dynamic.setObjectName("Plot_dynamic")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1613, 23))
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.Plot_static.setTitle(_translate("MainWindow", "StaticPlot"))
self.Static_plot.setText(_translate("MainWindow", "靜態(tài)作圖"))
self.dynamic_plot.setText(_translate("MainWindow", "動態(tài)作圖"))
self.End_plot.setText(_translate("MainWindow", "停止作圖"))
self.Erase_plot.setText(_translate("MainWindow", "清除數(shù)據(jù)"))
self.Plot_dynamic.setTitle(_translate("MainWindow", "DynamicPlot"))
邏輯–主要代碼分析
matplotlib作圖嵌入PyQt界面的關(guān)鍵
創(chuàng)建matlibplot圖形類Myplot,通過繼承FigureCanvas類,使其相當于PyQt里的控件,從而完成PyQt與Matlibplot的結(jié)合。
# class Myplot for plotting with matplotlib
class Myplot(FigureCanvas):
def __init__(self, parent=None, width=5, height=3, dpi=100):
# normalized for 中文顯示和負號
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# new fig
self.fig = Figure(figsize=(width, height), dpi=dpi)
# activate figure window
# super(Plot_dynamic,self).__init__(self.fig)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
# sub plot by self.axes
self.axes= self.fig.add_subplot(111)
# initial figure
self.compute_initial_figure()
# size policy
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
用于圖形初始化的圖像類,通過調(diào)用這個類就能實現(xiàn)圖形繪制和修改??梢栽诖烁膱D形的類型,具體代碼可以參照matplotlib官網(wǎng)的實例 Matplotlib_examples
class static_fig(Myplot):
def __init__(self,*args,**kwargs):
Myplot.__init__(self,*args,**kwargs)
def compute_initial_figure(self):
x=np.linspace(0,2*np.pi,100)
y=x*np.sin(x)
self.axes.plot(x,y)
self.axes.set_title("signals")
self.axes.set_xlabel("delay(s)")
self.axes.set_ylabel("counts")
主界面的邏輯代碼
幾點說明
1、利用Matplotlib自帶的NavigationToolbar可以實現(xiàn)繪制圖的基本操作:平移、放大、保存圖像、顯示鼠標位置(x,y)的數(shù)據(jù)等
2、self.gridlayout1.addWidget(self.fig1)就是把繪制的圖像本身作為一個控件widget加入UI界面里的groupbox(這里改成Plot_static名稱)去,從而使得圖形能正常顯示在繪圖框里。
class AppWindow(QMainWindow,Ui_MainWindow):
def __init__(self,parent=None):
super(AppWindow,self).__init__(parent)
self.setupUi(self)
# ^O^ static_fig can changed to any other function
#self.fig1=static_fig(width=5, height=4, dpi=100)
self.fig1 = static_fig(width=5, height=3, dpi=72)
self.fig2 = dynamic_fig(width=5, height=3, dpi=72)
# add NavigationToolbar in the figure (widgets)
self.fig_ntb1 = NavigationToolbar(self.fig1, self)
self.fig_ntb2 = NavigationToolbar(self.fig2, self)
#self.Start_plot.clicked.connect(self.plot_cos)
# add the static_fig in the Plot box
self.gridlayout1=QGridLayout(self.Plot_static)
self.gridlayout1.addWidget(self.fig1)
self.gridlayout1.addWidget(self.fig_ntb1)
# add the dynamic_fig in the Plot box
self.gridlayout2 = QGridLayout(self.Plot_dynamic)
self.gridlayout2.addWidget(self.fig2)
self.gridlayout2.addWidget(self.fig_ntb2)
self._timer = QTimer(self)
self._t = 1
self._counts = []
self._delay_t = []
靜態(tài)做圖
self.fig1.axes.cla()清除原來的圖像,self.fig1.axes.plot(self.t,self.y),通過self.fig1.axes.plot實現(xiàn)做圖,不同類型的圖形做圖參考matplotlib官網(wǎng)。 Matplotlib_examples
@pyqtSlot()
def on_Static_plot_clicked(self):
self.plot_cos()
self._Static_on=1
#self.Start_plot.setEnabled(False)
global nc
nc=1
def plot_cos(self):
#print('nc=%d\n' %self.nc)
global nc
nc+=1
self.fig1.axes.cla()
self.t=np.arange(0,15,0.1)
self.y=2*nc*self.t-self.t*np.cos(self.t/2/np.pi*1000)
self.fig1.axes.plot(self.t,self.y)
self.fig1.axes.set_title("signals",fontsize=18,color='c')
self.fig1.axes.set_xlabel("delay(s)",fontsize=18,color='c')
self.fig1.axes.set_ylabel("counts",fontsize=18,color='c')
self.fig1.draw()
動態(tài)做圖
這里數(shù)據(jù)接收通過QTimer來延遲時間(隔1s)并通過函數(shù)產(chǎn)生計數(shù),append更新數(shù)據(jù),做圖,刷新圖像,self.fig2.draw()實現(xiàn)圖像繪制。
@pyqtSlot()
def on_dynamic_plot_clicked(self):
print('start dynamic ploting')
self.Static_plot.setEnabled(False)
self.dynamic_plot.setEnabled(False)
# start update figure every 1s; flag "update_on" : 1 is on and 0 is Off
self._update_on = 1
self._timer.timeout.connect(self.update_fig)
self._timer.start(1000) # plot after 1s delay
def update_fig(self):
self._t+=1
print(self._t)
self._delay_t.append(self._t)
print(self._delay_t)
#new_counts=random.randint(100,900)
new_counts= 2 * self._t - self._t * np.cos(self._t / 2 / np.pi * 1000)
self._counts.append(new_counts)
print(self._counts)
self.fig2.axes.cla()
self.fig2.axes.plot(self._delay_t,self._counts,'-ob')
self.fig2.axes.set_title("signals",fontsize=18,color='c')
self.fig2.axes.set_xlabel("delay(s)",fontsize=18,color='c')
self.fig2.axes.set_ylabel("counts",fontsize=18,color='c')
self.fig2.draw()
改進說明
后續(xù)可以通過引入多線程,單獨進行數(shù)據(jù)采集、顯示和保存,完善功能。
最終完整代碼
# -*- coding: utf-8 -*-
"""
Module: plot data realtime.
Created on 2020/07/12 by Blog Author VERtiCaL at SSRF
"""
import matplotlib
matplotlib.use("Qt5Agg")
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5 import NavigationToolbar2QT as NavigationToolbar
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication,QMainWindow,QGridLayout
from PyQt5.QtCore import QTimer,pyqtSlot,QThread
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import numpy as np
import sys,random, time,os,re
from Ui_Realtimer_Plot import Ui_MainWindow
# class Myplot for plotting with matplotlib
class Myplot(FigureCanvas):
def __init__(self, parent=None, width=5, height=3, dpi=100):
# normalized for 中文顯示和負號
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# new figure
self.fig = Figure(figsize=(width, height), dpi=dpi)
# activate figure window
# super(Plot_dynamic,self).__init__(self.fig)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
#self.fig.canvas.mpl_connect('button_press_event', self)
# sub plot by self.axes
self.axes= self.fig.add_subplot(111)
# initial figure
self.compute_initial_figure()
# size policy
FigureCanvas.setSizePolicy(self,
QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
def compute_initial_figure(self):
pass
# class for plotting a specific figure static or dynamic
class static_fig(Myplot):
def __init__(self,*args,**kwargs):
Myplot.__init__(self,*args,**kwargs)
def compute_initial_figure(self):
x=np.linspace(0,2*np.pi,100)
y=x*np.sin(x)
self.axes.plot(x,y)
self.axes.set_title("signals")
self.axes.set_xlabel("delay(s)")
self.axes.set_ylabel("counts")
class dynamic_fig(Myplot):
def __init__(self,*args,**kwargs):
Myplot.__init__(self,*args,**kwargs)
def compute_initial_figure(self):
counts = [1,10]
delay_t = [0,1]
self.axes.plot(delay_t,counts,'-ob')
self.axes.set_title("signals")
self.axes.set_xlabel("delay(s)")
self.axes.set_ylabel("counts")
# class for the application window
class AppWindow(QMainWindow,Ui_MainWindow):
def __init__(self,parent=None):
super(AppWindow,self).__init__(parent)
self.setupUi(self)
# ^O^ static_fig can changed to any other function
#self.fig1=static_fig(width=5, height=4, dpi=100)
self.fig1 = static_fig(width=5, height=3, dpi=72)
self.fig2 = dynamic_fig(width=5, height=3, dpi=72)
# add NavigationToolbar in the figure (widgets)
self.fig_ntb1 = NavigationToolbar(self.fig1, self)
self.fig_ntb2 = NavigationToolbar(self.fig2, self)
#self.Start_plot.clicked.connect(self.plot_cos)
# add the static_fig in the Plot box
self.gridlayout1=QGridLayout(self.Plot_static)
self.gridlayout1.addWidget(self.fig1)
self.gridlayout1.addWidget(self.fig_ntb1)
# add the dynamic_fig in the Plot box
self.gridlayout2 = QGridLayout(self.Plot_dynamic)
self.gridlayout2.addWidget(self.fig2)
self.gridlayout2.addWidget(self.fig_ntb2)
# initialized flags for static/dynamic plot: on is 1,off is 0
self._timer = QTimer(self)
self._t = 1
self._counts = []
self._delay_t = []
self._Static_on=0
self._update_on=0
@pyqtSlot()
def on_Static_plot_clicked(self):
self.plot_cos()
self._Static_on=1
#self.Start_plot.setEnabled(False)
global nc
nc=1
def plot_cos(self):
#print('nc=%d\n' %self.nc)
global nc
nc+=1
self.fig1.axes.cla()
self.t=np.arange(0,15,0.1)
self.y=2*nc*self.t-self.t*np.cos(self.t/2/np.pi*1000)
self.fig1.axes.plot(self.t,self.y)
self.fig1.axes.set_title("signals",fontsize=18,color='c')
self.fig1.axes.set_xlabel("delay(s)",fontsize=18,color='c')
self.fig1.axes.set_ylabel("counts",fontsize=18,color='c')
self.fig1.draw()
@pyqtSlot()
def on_dynamic_plot_clicked(self):
print('start dynamic ploting')
self.Static_plot.setEnabled(False)
self.dynamic_plot.setEnabled(False)
# start update figure every 1s; flag "update_on" : 1 is on and 0 is Off
self._update_on = 1
self._timer.timeout.connect(self.update_fig)
self._timer.start(1000) # plot after 1s delay
def update_fig(self):
self._t+=1
print(self._t)
self._delay_t.append(self._t)
print(self._delay_t)
#new_counts=random.randint(100,900)
new_counts= 2 * self._t - self._t * np.cos(self._t / 2 / np.pi * 1000)
self._counts.append(new_counts)
print(self._counts)
self.fig2.axes.cla()
self.fig2.axes.plot(self._delay_t,self._counts,'-ob')
self.fig2.axes.set_title("signals",fontsize=18,color='c')
self.fig2.axes.set_xlabel("delay(s)",fontsize=18,color='c')
self.fig2.axes.set_ylabel("counts",fontsize=18,color='c')
self.fig2.draw()
@pyqtSlot()
def on_End_plot_clicked(self):
if self._update_on==1:
self._update_on=0
self._timer.timeout.disconnect(self.update_fig)
self.dynamic_plot.setEnabled(True)
else:
pass
@pyqtSlot()
def on_Erase_plot_clicked(self):
self.fig1.axes.cla()
self.fig1.draw()
self.fig2.axes.cla()
self.fig2.draw()
if self._update_on==1:
self._update_on=0
self._delay_t=[]
self._counts=[]
self.fig2.axes.cla()
self.fig2.draw()
self._timer.timeout.disconnect(self.update_fig)
self.dynamic_plot.setEnabled(True)
else:
pass
self.Static_plot.setEnabled(True)
#self.Erase_plot.setEnabled(False)
if __name__=="__main__":
app = QApplication(sys.argv)
win = AppWindow()
win.show()
sys.exit(app.exec_())
到此這篇關(guān)于利用PyQt5+Matplotlib 繪制靜態(tài)/動態(tài)圖的實現(xiàn)代碼的文章就介紹到這了,更多相關(guān)PyQt5+Matplotlib靜態(tài)/動態(tài)圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python中g(shù)lob庫實現(xiàn)文件名的匹配
本文主要主要介紹了Python中g(shù)lob庫實現(xiàn)文件名的匹配,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06
Python循環(huán)結(jié)構(gòu)的應(yīng)用場景詳解
這篇文章主要介紹了Python循環(huán)結(jié)構(gòu)的應(yīng)用場景詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07
Python基于unittest實現(xiàn)測試用例執(zhí)行
這篇文章主要介紹了Python基于unittest實現(xiàn)測試用例執(zhí)行,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-11-11
python機器學(xué)習(xí)實現(xiàn)oneR算法(以鳶尾data為例)
本文主要介紹了python機器學(xué)習(xí)實現(xiàn)oneR算法(以鳶尾data為例),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
詳解Python如何循環(huán)遍歷Numpy中的Array
Numpy是Python中常見的數(shù)據(jù)處理庫,是數(shù)據(jù)科學(xué)中經(jīng)常使用的庫。在本文中,我們將學(xué)習(xí)如何迭代遍歷訪問矩陣中的元素,需要的可以參考一下2022-04-04

