利用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判断端口是否打开的实现代码
Feb 10 Python
python使用cookielib库示例分享
Mar 03 Python
windows下Python实现将pdf文件转化为png格式图片的方法
Jul 21 Python
Python单体模式的几种常见实现方法详解
Jul 28 Python
python虚拟环境virtualenv的使用教程
Oct 20 Python
Python决策树之基于信息增益的特征选择示例
Jun 25 Python
Python中的Numpy矩阵操作
Aug 12 Python
Python中面向对象你应该知道的一下知识
Jul 10 Python
浅谈pytorch卷积核大小的设置对全连接神经元的影响
Jan 10 Python
Python pip install如何修改默认下载路径
Apr 29 Python
详解用Python爬虫获取百度企业信用中企业基本信息
Jul 02 Python
Python selenium键盘鼠标事件实现过程详解
Jul 28 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
关于手调机和数调机的选择
2021/03/02 无线电
php获取字段名示例分享
2014/03/03 PHP
php格式化电话号码的方法
2015/04/24 PHP
CodeIgniter使用smtp服务发送html邮件的方法
2015/06/10 PHP
PHP的全局错误处理详解
2016/04/25 PHP
JavaScript面向对象之体会[总结]
2008/11/13 Javascript
javascript获取当前ip的代码
2009/05/10 Javascript
js DOM 元素ID就是全局变量
2012/09/20 Javascript
js同比例缩放图片的小例子
2013/10/30 Javascript
JavaScript动态操作表格实例(添加,删除行,列及单元格)
2013/11/25 Javascript
实例分析javascript中的call()和apply()方法
2014/11/28 Javascript
Sortable.js拖拽排序使用方法解析
2016/11/04 Javascript
Angularjs根据json文件动态生成路由状态的实现方法
2017/04/17 Javascript
详解Angular之constructor和ngOnInit差异及适用场景
2017/06/22 Javascript
vue 国际化 vue-i18n 双语言 语言包
2018/06/07 Javascript
Vue 中 a标签上href无法跳转的解决方式
2019/11/12 Javascript
Python自动连接ssh的方法
2015/03/07 Python
用Python编写一个简单的FUSE文件系统的教程
2015/04/02 Python
简单谈谈python中的多进程
2016/11/06 Python
zookeeper python接口实例详解
2018/01/18 Python
Python使用Tkinter实现机器人走迷宫
2018/01/22 Python
python解决字符串倒序输出的问题
2018/06/25 Python
python迭代dict的key和value的方法
2018/07/06 Python
python清空命令行方式
2020/01/13 Python
HTML5学习心得总结(推荐)
2016/07/08 HTML / CSS
凯普林包包西班牙官网:Kipling西班牙
2019/04/12 全球购物
飞利浦西班牙官方网站:Philips西班牙
2020/02/17 全球购物
2014年会演讲稿范文
2014/01/06 职场文书
上课玩手机检讨书
2014/02/08 职场文书
出纳员岗位责任制
2014/02/11 职场文书
授权委托书范文
2014/07/31 职场文书
2014年项目经理工作总结
2014/11/24 职场文书
2015年基层党组织公开承诺书
2015/01/21 职场文书
合理化建议书范文
2015/09/14 职场文书
“学党章、守党纪、讲党规”学习心得体会
2016/01/14 职场文书
Vue Element-ui表单校验规则实现
2021/07/09 Vue.js