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

代碼塊(業(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", "動(dòng)態(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圖形類(lèi)Myplot,通過(guò)繼承FigureCanvas類(lèi),使其相當(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 中文顯示和負(fù)號(hào)
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
用于圖形初始化的圖像類(lèi),通過(guò)調(diào)用這個(gè)類(lèi)就能實(shí)現(xiàn)圖形繪制和修改??梢栽诖烁膱D形的類(lèi)型,具體代碼可以參照matplotlib官網(wǎng)的實(shí)例 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")
主界面的邏輯代碼
幾點(diǎn)說(shuō)明
1、利用Matplotlib自帶的NavigationToolbar可以實(shí)現(xiàn)繪制圖的基本操作:平移、放大、保存圖像、顯示鼠標(biāo)位置(x,y)的數(shù)據(jù)等
2、self.gridlayout1.addWidget(self.fig1)就是把繪制的圖像本身作為一個(gè)控件widget加入U(xiǎn)I界面里的groupbox(這里改成Plot_static名稱(chēng))去,從而使得圖形能正常顯示在繪圖框里。
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()清除原來(lái)的圖像,self.fig1.axes.plot(self.t,self.y),通過(guò)self.fig1.axes.plot實(shí)現(xiàn)做圖,不同類(lèi)型的圖形做圖參考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()
動(dòng)態(tài)做圖
這里數(shù)據(jù)接收通過(guò)QTimer來(lái)延遲時(shí)間(隔1s)并通過(guò)函數(shù)產(chǎn)生計(jì)數(shù),append更新數(shù)據(jù),做圖,刷新圖像,self.fig2.draw()實(shí)現(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()
改進(jìn)說(shuō)明
后續(xù)可以通過(guò)引入多線程,單獨(dú)進(jìn)行數(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 中文顯示和負(fù)號(hào)
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)/動(dòng)態(tài)圖的實(shí)現(xiàn)代碼的文章就介紹到這了,更多相關(guān)PyQt5+Matplotlib靜態(tài)/動(dòng)態(tài)圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- PyQt5 matplotlib畫(huà)圖不刷新的解決方案
- PyQt5結(jié)合matplotlib繪圖的實(shí)現(xiàn)示例
- 詳解pyqt5的UI中嵌入matplotlib圖形并實(shí)時(shí)刷新(挖坑和填坑)
- pyqt5與matplotlib的完美結(jié)合實(shí)例
- python GUI庫(kù)圖形界面開(kāi)發(fā)之PyQt5滾動(dòng)條控件QScrollBar詳細(xì)使用方法與實(shí)例
- 在PYQT5中QscrollArea(滾動(dòng)條)的使用方法
- PyQt5實(shí)現(xiàn)將Matplotlib圖像嵌入到Scoll Area中顯示滾動(dòng)條效果
相關(guān)文章
Python中g(shù)lob庫(kù)實(shí)現(xiàn)文件名的匹配
本文主要主要介紹了Python中g(shù)lob庫(kù)實(shí)現(xiàn)文件名的匹配,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-06-06
Python循環(huán)結(jié)構(gòu)的應(yīng)用場(chǎng)景詳解
這篇文章主要介紹了Python循環(huán)結(jié)構(gòu)的應(yīng)用場(chǎng)景詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
Python基于unittest實(shí)現(xiàn)測(cè)試用例執(zhí)行
這篇文章主要介紹了Python基于unittest實(shí)現(xiàn)測(cè)試用例執(zhí)行,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
Pycharm安裝scrapy及初始化爬蟲(chóng)項(xiàng)目的完整步驟
因?yàn)槿腴T(mén)python以來(lái)一直使用pycharm,所以對(duì)著黑白的DOS不習(xí)慣,所以此次來(lái)實(shí)現(xiàn)使用pycharm進(jìn)行實(shí)現(xiàn)使用scrapy框架,下面這篇文章主要給大家介紹了關(guān)于Pycharm安裝scrapy及初始化爬蟲(chóng)項(xiàng)目的完整步驟,需要的朋友可以參考下2022-08-08
python機(jī)器學(xué)習(xí)實(shí)現(xiàn)oneR算法(以鳶尾data為例)
本文主要介紹了python機(jī)器學(xué)習(xí)實(shí)現(xiàn)oneR算法(以鳶尾data為例),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
詳解Python如何循環(huán)遍歷Numpy中的Array
Numpy是Python中常見(jiàn)的數(shù)據(jù)處理庫(kù),是數(shù)據(jù)科學(xué)中經(jīng)常使用的庫(kù)。在本文中,我們將學(xué)習(xí)如何迭代遍歷訪問(wèn)矩陣中的元素,需要的可以參考一下2022-04-04

