GUI程序中的Matplotlib绘图

1.示例程序和运行效果

一般的书上介绍Matplotlib的绘图功能都主要是介绍matplotlib.pyplot模块中的指令式绘图功能,因为这种方式与MATLAB很相似,使用过MATLAB的人转而使用Matplotlib绘图会比较容易上手。但是这种方式将绘图的效果都固定在程序里了,例如曲线的颜色、线条类型等,如果要修改就需要修改源程序重新运行,所以这种方式只适合做研究时的快速数据可视化,不能做成GUI应用程序进行交互式绘图。

Matplotlib是完全采用面向对象方法设计的,图的各个组成元素,如图、子图、坐标轴、曲线等都有相应的类,还有各种涉及图的操作的类。通过类的接口函数和属性可以对图的各个组成元素进行完全的控制,这种方法称为面向对象(Object-Oriented,OO)方法。面向对象方法适合在GUI应用程序中使用,因为在程序中可以对这些对象实例进行操作。

下面先用一个简单的程序演示在GUI应用程序中使用Matplotlib的面向对象方法绘图的基本方法。示例Demo14_1目录下的文件Demo14_1GUI.py的完整代码如下:

  1. ## 程序文件: Demo14_1GUI.py
  2. ## 使用matplotlib 面向对象方法在GUI中绘图
  3. import sys
  4. import numpy as np
  5. import matplotlib as mpl
  6. from matplotlib.backends.backend_qt5agg import (FigureCanvas,
  7. NavigationToolbar2QT as NavigationToolbar)
  8. from PyQt5.QtWidgets import QApplication, QMainWindow
  9. from PyQt5.QtCore import Qt
  10.  
  11. class QmyMainWindow(QMainWindow):
  12. def __init__(self, parent=None):
  13. super().__init__(parent) #调用父类构造函数
  14. self.setWindowTitle("Demo14_1, GUI中的matplotlib绘图")
  15. ## rcParams[]参数设置,以正确显示汉字
  16. mpl.rcParams['font.sans-serif']=['KaiTi','SimHei'] #汉字字体
  17. mpl.rcParams['font.size']=12 #字体大小
  18. mpl.rcParams['axes.unicode_minus'] =False #正常显示负号
  19. self.__iniFigure() #创建绘图系统,初始化窗口
  20. self.__drawFigure() #绘图
  21.  
  22. ##==========自定义函数=================
  23. def __iniFigure(self): ##创建绘图系统,初始化窗口
  24. self.__fig=mpl.figure.Figure(figsize=(8, 5)) #单位英寸
  25. self.__fig.suptitle("plot in GUI application") #总的图标题
  26. figCanvas = FigureCanvas(self.__fig) #创建FigureCanvas对象
  27. naviToolbar=NavigationToolbar(figCanvas, self) #创建工具栏
  28. naviToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
  29. self.addToolBar(naviToolbar) #添加工具栏到主窗口
  30. self.setCentralWidget(figCanvas)
  31.  
  32. def __drawFigure(self): ##绘图
  33. t = np.linspace(0, 10, 40)
  34. y1=np.sin(t)
  35. y2=np.cos(2*t)
  36.  
  37. ax1=self.__fig.add_subplot(1,2,1) #matplotlib.axes.Axes 类
  38. ax1.plot(t,y1,'r-o',label="sin", linewidth=1, markersize=5)
  39. ax1.plot(t,y2,'b:',label="cos",linewidth=2)
  40. ax1.set_xlabel('X 轴') #x轴标题
  41. ax1.set_ylabel('Y 轴',fontsize=14) #y轴标题
  42. ax1.set_xlim([0,10])
  43. ax1.set_ylim([-1.5,1.5])
  44. ax1.set_title("曲线") #子图标题
  45. ax1.legend() #自动创建图例
  46.  
  47. ax2=self.__fig.add_subplot(1,2,2) #matplotlib.axes.Axes 类
  48. week=["Mon","Tue","Wed","Thur","Fri","Sat","Sun"]
  49. sales=np.random.randint(200,400,7)
  50. ax2.bar(week,sales) #绘制柱状图
  51. ax2.set_xlabel('week days') #x轴标题
  52. ax2.set_ylabel('参观人数') #y轴标题
  53. ax2.set_title("柱状图") #子图标题
  54.  
  55. ## ============窗体测试程序 ================================
  56. if __name__ == "__main__":
  57. app = QApplication(sys.argv)
  58. form=QmyMainWindow()
  59. form.show()
  60. sys.exit(app.exec_())

程序运行时的界面如图 14-2所示。注意这个程序是用PyQt5的GUI应用程序框架创建的。为了减少程序的复杂度,没有使用可视化方法设计UI窗体,而是采用纯代码的方式。程序中定义了一个基于QMainWindow的窗口类QmyMainWindow,界面构造和绘图都是在QmyMainWindow的构造函数中实现的。

 

图14-2 使用Matplotlib绘图的PyQt5 GUI程序界面

2.后端(backend)

Matplotlib的绘图结果可以有各种输出形式,例如在Python交互式环境中输出绘图结果,嵌入到wxpython、pygtk、Qt等GUI框架中输出绘图结果,将绘图结果输出为图片文件,或在Web应用程序中输出绘图结果。要实现这些不同的输出,Matplotlib需要有不同的处理方法,这些不同的输出功能就称为后端(backend)。而相对的就是前端(frontend),是用户面对的代码。例如,对于一段相同的前端绘图代码,后端就是实现场景后面的工作以生成绘图输出。

有两种后端,一种是用户界面后端(也称为交互式后端),例如用于wxpython、pygtk、tkinter、qt4、qt5、macosx的后端,另一种是用于生成图片文件的后端,如生成PNG、SVG、PDF等文件。

对于用户界面后端,Matplotlib还将渲染器(renderer)和画布(canvas)分离开来,以实现更灵活的定制功能。Matplotlib使用的主要的渲染器是基于Anti-Grain Geometry C++库的Agg渲染器。除了macosx,所有的用户界面都使用Agg渲染器,因而有WXAgg、GTK3Agg、QT4Agg、QT5Agg、TkAgg等。有些用户界面也支持其他的渲染器,如Cairo渲染器,因而有GTK3Cairo、QT4Cairo、QT5Cairo等。

在Matplotlib安装目录的“backends”子目录里是这些后端的模块文件,例如有backend_ gtk3agg.py、backend_gtk3cairo.py、backend_qt5agg.py、backend_qt5cairo.py等。本书只考虑QT5Agg渲染器,所以在程序的import部分有如下的语句:

 
  1. from matplotlib.backends.backend_qt5agg import (
  2. FigureCanvas, NavigationToolbar2QT as NavigationToolbar)

这是从matplotlib.backends.backend_qt5agg模块中导入了FigureCanvas类和NavigationToolbar2QT类,并将NavigationToolbar2QT类重命名为NavigationToolbar。

追踪查看FigureCanvas类的源程序,可以发现它的上层父类之一是QWidget,所以,它是用于在PyQt5 GUI界面上显示Matplotlib绘图结果的Widget组件。要在PyQt5 GUI窗体上显示Matplotlib绘图结果,必须创建一个FigureCanvas界面组件,就如同使用PyQtChart模块绘制图表时需要先创建一个QChartView界面组件。

3.程序解读

(1)为正常显示汉字的设置

在自定义类QmyMainWindow的构造函数里实现窗体界面构造和Matplotlib绘图。

首先对Matplotlib的全局设置做一些修改,以便正确显示汉字。可以修改全局字典变量matplotlib.rcParams里的参数,也可以修改配置文件matplotlibrc的内容。程序中的设置语句如下:

  1. mpl.rcParams['font.sans-serif']=['KaiTi','SimHei'] #汉字字体
  2. mpl.rcParams['font.size']=12 #字体大小
  3. mpl.rcParams['axes.unicode_minus'] =False #正常显示负号

第1行语句是设置字体族(font family)“sans-serif”的参数,第3行语句是为了正常显示负号。

Matplotlib中将字体分为5种字体族,分别是“serif”“sans-serif”“cursive”“fantasy”“monospace”,每一种字体族可以设定多种字体。在默认的matplotlibrc文件中使用的字体族是“sans-serif”,这个字体族的字体不包含汉字字体,所以无法正常显示汉字。

第1行语句将’font.sans-serif’参数设置为[‘KaiTi’, ‘SimHei’],Matplotlib将优先使用字体’KaiTi’,如果找不到这个字体的字体文件,就使用后面的字体’SimHei’,可以为一个字体族设置多个字体。Windows系统中常见的汉字字体名称如下。

  • KaiTi =楷体;SimHei=黑体;FangSong=仿宋。
  • STSong=华文宋体;STFangsong=华文仿宋;STHeiti=华文黑体。

关于字体的设置可以查看配置文件matplotlibrc的默认内容,在Matplotlib 3.0.0用户手册的第89页。

(2)创建绘图界面组件的函数__iniFigure()

构造函数里调用自定义函数__iniFigure()创建绘图相关的界面组件,此函数的完整代码见前面的程序清单。程序首先创建了一个matplotlib.figure.Figure类对象self.__fig:

  1. self.__fig=mpl.figure.Figure(figsize=(8, 5)) #单位英寸

Figure类就是用于绘图的图表类,是Matplotlib中一个主要的类,它负责管理一个图形窗口中子图、各种图表组件的绘制,其功能类似于PyQtChart模块中的QChart类。但是一个Figure里可以绘制多个子图,而QChart只能绘制一个图表。

创建FigureCanvas对象时必须传递一个Figure类对象,程序中是:

  1. figCanvas = FigureCanvas(self.__fig) #创建FigureCanvas对象

这样,Figure类对象self.__fig就用figCanvas作为图形渲染区域(画布),self.__fig的各种绘图操作都在此画布上显示出来。

创建NavigationToolbar类导航工具栏naviToolbar时传递一个FigureCanvas对象作为参数,即

  1. naviToolbar=NavigationToolbar(figCanvas, self) #创建工具栏

这样创建的导航工具栏的操作就是针对关联的FigureCanvas类对象figCanvas。Navigation- Toolbar的父类是QToolBar,所以可以使用setToolButtonStyle()函数设置按钮显示方式,并且添加它作为主窗口的工具栏。

程序运行时,图14-2中的工具栏与图14-1中的工具栏有些差异,例如图14-2的工具栏中有“Customize”按钮对子图进行设置,而图14-1的工具栏中没有这个按钮。两个工具栏的“Subplots”按钮弹出的对话框的界面也不同,这就是由于使用了不同的后端引起的。

FigureCanvas的父类是QWidget,所以其对象示例可以作为主窗口的中心组件。Navigation- Toolbar和FigureCanvas还有其他的一些功能,在后面再具体介绍。

(3)实现绘图功能的函数__drawFigure()

构造函数里调用自定义函数__drawFigure()绘图,其完整代码参见前面的代码清单。

函数__drawFigure()实现的绘图功能与程序Demo14_1Script.py中的几乎相同,但是实现的方法不同。在文件Demo14_1GUI.py的import部分没有导入matplotlib.pyplot,它完全使用面向对象的方法绘图。

在使用NumPy的功能准备好数据后,程序首先创建了一个子图,代码是:

  1. ax1=self.__fig.add_subplot(1,2,1) #子图1

self.__fig是matplotlib.figure.Figure类对象,是整个图。使用Figure.add_subplot()函数创建了一个对象ax1。函数Figure.add_subplot()与matplotlib.pyplot.subplot()参数格式和功能完全相同,这里不再对参数做详细的说明,读者可以通过内建函数help()获取该函数的详细帮助信息,输入指令是:

  1. >>> from matplotlib.figure import Figure
  2. >>> help (Figure.add_subplot)

这里创建的对象ax1是matplotlib.figure.Axes类型,它是管理一个子图区域绘图的类。通过Axes类的接口函数在子图区域画图,例如ax1使用plot()函数绘制了两条曲线,Axes.plot()函数的使用方法与matplotlib.pyplot.plot()函数相同。

Axes类通过属性和接口函数对子图的各个组成元素,如曲线、坐标轴范围、标题、网格线、图例等进行操作。一般通过一组set_和get_函数对一个属性进行设置和获取,例如Axes.set_xlim()函数设置x轴坐标范围,Axes.get_xlim()函数返回x轴的坐标范围。这与matplotlib.pyplot模块中的操作方法不同,pyplot.xlim()函数既可以设置x轴坐标范围,也可以返回x轴坐标范围。

Axes类是Matplotlib绘图中最主要的一个类,一个子图上的所有元素都由Axes管理,所以在GUI中进行Matplotlib绘图主要就是Axes类及其管理的各个子对象的操作,如坐标轴(Axis类)、曲线(Line2D类)、文本(Text类)、图例(Legend类)的操作。这些操作都使用面向对象的方法,与matplotlib.pyplot中的指令式操作的方法不同,但实现的功能相同。

本节先通过一个简单示例演示了在GUI程序中使用Matplotlib绘图的基本方法,下一节再对Matplotlib绘图时常用到的各个类的使用方法进行详细介绍。

本文截选自《Python Qt GUI与数据可视化编程》
王维波,栗宝鹃,张晓东 著

 

  • PyQt5教程书籍,pyqt5快速开发实例教程
  • PythonQt5GUI快速编程
  • 示例丰富的PythonGUI编程和数据可视化编程的实用指南

本书介绍在Python中使用PyQt5和其他模块进行GUI和数据可视化编程的方法。第一部分介绍PyQt5设计GUI程序的基本框架,包括GUI应用程序的基本结构、窗体UI可视化设计与窗体业务逻辑的设计、信号与槽的特点和使用等。第二部分介绍GUI程序设计中一些主要功能模块的使用,包括基本界面组件、事件处理、数据库、绘图、多媒体等。第三部分先介绍使用PyQtChart和PyQtDataVisualization进行二维和三维数据可视化设计的方法,再介绍将Matplotlib嵌入PyQt5 GUI应用程序窗口界面中进行数据可视化的编程方法。通过研读本书,读者可以掌握使用PyQt5、PyQtChart、Matplotlib等模块进行GUI应用程序和数据可视化设计的方法。

本书适合具有Python编程基础,并想通过Python设计GUI应用程序或在GUI应用程序中实现数据可视化的读者阅读和参考。

  • 2
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值