利用PyQt5+Matplotlib 绘制静态/动态图的实现代码


Posted in Python onJuly 13, 2020

代码编辑环境

Win10+(Pycharmm or Vscode)+PyQt 5.14.2

功能实现

静态作图:数据作图,取决于作图函数,可自行修改
动态作图:产生数据,获取并更新数据,最后刷新显示,可用于实现数据实时采集并显示的场景

效果展示

利用PyQt5+Matplotlib 绘制静态/动态图的实现代码

代码块(业务与逻辑分离)业务?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", "静态作图"))
    self.dynamic_plot.setText(_translate("MainWindow", "动态作图"))
    self.End_plot.setText(_translate("MainWindow", "停止作图"))
    self.Erase_plot.setText(_translate("MainWindow", "清除数据"))
    self.Plot_dynamic.setTitle(_translate("MainWindow", "DynamicPlot"))

逻辑?主要代码分析

matplotlib作图嵌入PyQt界面的关键

创建matlibplot图形类Myplot,通过继承FigureCanvas类,使其相当于PyQt里的控件,从而完成PyQt与Matlibplot的结合。

# 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

用于图形初始化的图像类,通过调用这个类就能实现图形绘制和修改。可以在此更改图形的类型,具体代码可以参照matplotlib官网的实例 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可以实现绘制图的基本操作:平移、放大、保存图像、显示鼠标位置(x,y)的数据等
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 = []

静态做图

self.fig1.axes.cla()清除原来的图像,self.fig1.axes.plot(self.t,self.y),通过self.fig1.axes.plot实现做图,不同类型的图形做图参考matplotlib官网。 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()

动态做图

这里数据接收通过QTimer来延迟时间(隔1s)并通过函数产生计数,append更新数据,做图,刷新图像,self.fig2.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()

改进说明

后续可以通过引入多线程,单独进行数据采集、显示和保存,完善功能。

最终完整代码

# -*- 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_())

到此这篇关于利用PyQt5+Matplotlib 绘制静态/动态图的实现代码的文章就介绍到这了,更多相关PyQt5+Matplotlib静态/动态图内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python爬取qq music中的音乐url及批量下载
Mar 23 Python
5款非常棒的Python工具
Jan 05 Python
python Spyder界面无法打开的解决方法
Apr 27 Python
分享一下Python数据分析常用的8款工具
Apr 29 Python
详解python中的hashlib模块的使用
Apr 22 Python
python利用re,bs4,requests模块获取股票数据
Jul 29 Python
Python 取numpy数组的某几行某几列方法
Oct 24 Python
python相对企业语言优势在哪
Jun 12 Python
Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取
Jun 30 Python
Python中zipfile压缩包模块的使用
May 14 Python
python字符串的一些常见实用操作
Apr 06 Python
python使用BeautifulSoup 解析HTML
Apr 24 Python
Python使用itcaht库实现微信自动收发消息功能
Jul 13 #Python
解决Pycharm 中遇到Unresolved reference 'sklearn'的问题
Jul 13 #Python
解决Python中导入自己写的类,被划红线,但不影响执行的问题
Jul 13 #Python
浅析Python 抽象工厂模式的优缺点
Jul 13 #Python
python正则表达式的懒惰匹配和贪婪匹配说明
Jul 13 #Python
浅析Python 简单工厂模式和工厂方法模式的优缺点
Jul 13 #Python
对python中list的五种查找方法说明
Jul 13 #Python
You might like
php将mysql数据库整库导出生成sql文件的具体实现
2014/01/08 PHP
PHP答题类应用接口实例
2015/02/09 PHP
php使用正则验证中文
2016/04/06 PHP
PHP之十六个魔术方法详细介绍
2016/11/01 PHP
php使用PDO获取结果集的方法
2017/02/16 PHP
用js计算页面执行时间的函数
2006/12/07 Javascript
js、jquery图片动画、动态切换示例代码
2014/06/03 Javascript
中文输入法不触发onkeyup事件的解决办法
2014/07/09 Javascript
触屏中的JavaScript事件分析
2015/02/06 Javascript
js实现的倒计时按钮实例
2015/06/24 Javascript
js实现获取div坐标的方法
2015/11/16 Javascript
JS获取随机数和时间转换的简单实例
2016/07/10 Javascript
Three.js学习之几何形状
2016/08/01 Javascript
jQuery.uploadify文件上传组件实例讲解
2016/09/23 Javascript
简单实现JS计算器功能
2016/12/21 Javascript
JavaScript高阶函数_动力节点Java学院整理
2017/06/28 Javascript
浅谈Webpack 是如何加载模块的
2018/05/24 Javascript
vue移动端项目缓存问题实践记录
2018/10/29 Javascript
使用typescript改造koa开发框架的实现
2020/02/04 Javascript
在Mac OS上使用mod_wsgi连接Python与Apache服务器
2015/12/24 Python
深入解析Python中的线程同步方法
2016/06/14 Python
Python实现将MySQL数据库表中的数据导出生成csv格式文件的方法
2018/01/11 Python
python实现微信自动回复功能
2018/04/11 Python
Python 查看list中是否含有某元素的方法
2018/06/27 Python
如何用python写一个简单的词法分析器
2018/12/18 Python
django与小程序实现登录验证功能的示例代码
2019/02/19 Python
20行python代码实现人脸识别
2019/05/05 Python
python自制包并用pip免提交到pypi仅安装到本机【推荐】
2019/06/03 Python
对Python 检查文件名是否规范的实例详解
2019/06/10 Python
澳大利亚女士时装在线:Rockmans
2018/09/26 全球购物
Oracle中delete,truncate和drop的区别
2016/05/05 面试题
实习教师自我鉴定
2013/12/09 职场文书
庆祝教师节演讲稿
2014/09/03 职场文书
公文格式,规则明细(新手收藏)
2019/07/23 职场文书
Python实战之实现康威生命游戏
2021/04/26 Python
JavaScript实现栈结构详细过程
2021/12/06 Javascript