利用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類,使其相當(dāng)于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)圖形繪制和修改。可以在此更改圖形的類型,具體代碼可以參照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)繪制圖的基本操作:平移、放大、保存圖像、顯示鼠標(biāo)位置(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)文章
Django ForeignKey與數(shù)據(jù)庫的FOREIGN KEY約束詳解
這篇文章主要介紹了Django ForeignKey與數(shù)據(jù)庫的FOREIGN KEY約束詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-05-05python re模塊findall()函數(shù)實例解析
這篇文章主要介紹了python re模塊findall()函數(shù)實例解析,具有一定借鑒價值,需要的朋友可以參考下2018-01-01python使用梯度下降和牛頓法尋找Rosenbrock函數(shù)最小值實例
這篇文章主要介紹了python使用梯度下降和牛頓法尋找Rosenbrock函數(shù)最小值實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04