Matplotlib系列目录
matplotlib可以很容易嵌入PyQt、GTK、Tk、wxPython以及Web中。这里只介绍嵌入PyQt(PySide)。
Matplotlib系列将Matplotlib的知识和重点API,编制成思维导图和重点笔记形式,方便记忆和回顾,也方便应用时参考,初学者也可以参考逐步深入学习。
matplotlib嵌入GUI时,首先需要确定界面渲染引擎,并导入渲染引擎对应的画布
以Qt(PyQt或PySide)为例:
import matplotlib
matplotlib.use('QtAgg') #指定渲染后端。QtAgg后端指用Agg二维图形库在Qt控件上绘图。
from matplotlib.backends.backend_qtagg import FigureCanvas
#使用matplotlib中的FigureCanvas(继承自QtWidgets.QWidget)绘制图形可以嵌入QT GUI
创建FigureCanvas时需要传入一个figure作为参数用于绘图:
canvas=FigureCanvas(figure)
matplotlib显示图形实际上通过第三方库作为后端实现的,即调用后端的接口渲染图形。
matplotlib有多种后端,并且很多后端还有多种可选的UI引擎:
可用的后端简介如下(后端名称不区分大小写)
以上后端名称都可以用于matplotlib.use函数
有三种设置后端引擎的方法:
matplotlib.use('agg')
rcParams["backend"] = 'agg'
MPLBACKEND
环境变量默认后端为’agg’。后端名称字符串不分大小写。
对于qt。QtAgg和QtCairo后端同时支持Qt5和Qt6。Qt5Agg同时支持PyQt5和Pyside2。
那么matplotlib会使用pyqt还是pyside作为引擎呢?
QT_API环境变量
确定。
QT_API环境变量
可以设置为PyQt6,PySide6,PyQt5,PySide2,PyQt4或PyQt4v2。不分大小写QT_API环境变量
的后端不存在,则自动尝试导入
Matplotlib还将后端渲染器(renderer)和画布(canvas)分离开来,以实现更灵活的定制功能。画布就是一个GUI的控件,可以直接嵌入GUI中。
在Matplotlib安装目录的“backends”子目录里是这些后端的模块文件,例如有
推荐做法:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qtagg import FigureCanvas #FigureCanvas是FigureCanvasQTAgg的别名。
fig = plt.figure()
cav = FigureCanvas(fig) #创建matplotlib画布
from matplotlib.backends.backend_qt5agg import FigureCanvas实际上和上边代码效果一样,同样能用于qt6。只是为了兼容旧API。
FigureCanvas类继承自QWidget,所以,FigureCanvas就是个Widget组件,可以直接嵌入GUI窗体上。
基于qt的后端还有backend_qtcairo、backend_qt5agg、backend_qt、backend_agg。通常建议使用backend_qtagg
- backend_qtcairo需要安装pycairo或cairocffi
- backend_qt5agg实际上就是从backend_qtagg导入的,和backend_qtagg完全相同,并非针对qt5的,主要为了兼容老版本
- backend_qtagg同时继承了backend_qt和backend_agg。单独使用backend_qt和backend_agg会有很多功能缺失,甚至不能绘图,需要自行写很多代码
import sys
import numpy as np
from qtpy.QtWidgets import QApplication #qtpy会以PyQt5,PyQt6,PySide2,PySide6的顺序依次尝试import。
from matplotlib.backends.backend_qtagg import FigureCanvas
import matplotlib.pyplot as plt
app=QApplication(sys.argv) #创建QApplication
fig = plt.figure() #创建figure
ax = fig.subplots()
t = np.linspace(0,np.pi,50)
ax.plot(t,np.sin(t)) #画曲线(在窗口显示之后画也可以)
win=FigureCanvas(fig) #创建画布控件
win.show() #画布控件作为窗口显示
sys.exit(app.exec()) #启动App事件循环
注意,示例中并没有使用matplotlib.use指定qt绑定库版本。因为我们从backend_qtagg导入了FigureCanvas,所以matplotlib自动将后端设置为qtagg,所以不需要再重复设置了。
一般情况下,matplotlib嵌入GUI的时候都不需要再调用matplotlib.use。
在不需要嵌入GUI,安装了多个GUI库,又想指定后端的时候可以显示调用matplotlib.use。
qtpy是一个把PyQt和PySide多个版本api抽象为统一接口的小型库。
qtpy导入Python Qt绑定库的规则为:
- 如果已经导入了PyQt6,PyQt5,PySide6或PySide2则直接使用。
- 如果FORCE_QT_API环境变量为True,则优先用
QT_API环境变量
确定。- 如果没有已经导入的库,则从
QT_API环境变量
确定。
- 环境变量可以是PyQt6,PyQt5,PySide6或PySide2(不区分大小写)。
- 如果环境变量指定的库没有安装则出错。
- 如果没有没有设置环境变量,则以PyQt5,PyQt6,PySide2,PySide6的顺序依次尝试import。
使用from matplotlib.backends.compat import QtWidgets能达到from qtpy import QtWidgets类似的效果。
每个backend后端都定义了一个NavigationToolbar类,可以用于显示matplotlib图形的工具栏。
from matplotlib.backends.backend_qtagg import NavigationToolbar2QT as NavigationToolbar
...
toolbar=NavigationToolbar(figurecanvas, parent)
...
从matplotlib.backends.backend_qtagg模块中导入了NavigationToolbar2QT类,并重命名为NavigationToolbar。
NavigationToolbar也是一个QWidget控件,可以直接嵌入GUI窗体上。
import sys
import numpy as np
from qtpy.QtWidgets import QApplication, QWidget, QVBoxLayout
from matplotlib.backends.backend_qtagg import FigureCanvas, NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
class MainWin(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("matplotlib embeded in Python Qt with figure toolbar")
self.initUI()
self.plotfig()
def initUI(self):
self.fig = plt.figure() #创建figure对象
self.canvas=FigureCanvas(self.fig) #创建figure画布
self.figtoolbar=NavigationToolbar(self.canvas, self) #创建figure工具栏
vlayout=QVBoxLayout()
vlayout.addWidget(self.canvas) #画布添加到窗口布局中
vlayout.addWidget(self.figtoolbar) #工具栏添加到窗口布局中
self.setLayout(vlayout)
def plotfig(self): #绘制matplot图形
ax = self.fig.subplots()
t = np.linspace(0,2*np.pi,50)
ax.plot(t,np.sin(t))
ax.autoscale_view()
app=QApplication(sys.argv)
win = MainWin()
win.show()
sys.exit(app.exec())
应用程序与嵌入GUI的matplotlib图形交互实际上就是对Figure、FigureCanvas和NavigationToolbar进行操作。除了绘图函数外,比较有用的函数汇总如下:
import sys
import numpy as np
from qtpy.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,QPushButton
from matplotlib.backends.backend_qtagg import FigureCanvas, NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
class MainWin(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("matplotlib embeded in Python Qt")
self.initUI()
self.plotfig()
def initUI(self):
self.fig = plt.figure()
self.canvas=FigureCanvas(self.fig)
self.figtoolbar=NavigationToolbar(self.canvas, self)
self.btn_start=QPushButton("start")
self.btn_pause=QPushButton("pause")
hlayout=QHBoxLayout()
hlayout.addStretch(1)
hlayout.addWidget(self.btn_start)
hlayout.addWidget(self.btn_pause)
hlayout.addStretch(1)
vlayout=QVBoxLayout()
vlayout.addWidget(self.figtoolbar)
vlayout.addWidget(self.canvas)
vlayout.addLayout(hlayout)
widget=QWidget()
widget.setLayout(vlayout)
self.setCentralWidget(widget)
def plotfig(self):
ax = self.fig.subplots()
self.t = np.linspace(0,2*np.pi,50)
self.lines=ax.plot(np.sin(self.t))
ax.autoscale_view()
def aniupdate(i):
t=self.t+2*np.pi*i/50
self.lines[0].set_ydata(np.sin(t))
return self.lines
self.ani=FuncAnimation(self.fig, aniupdate, interval=100)
self.btn_start.clicked.connect(self.ani.resume)
self.btn_pause.clicked.connect(self.ani.pause)
app=QApplication(sys.argv)
win = MainWin()
win.show()
sys.exit(app.exec())
Matplotlib系列目录
个人总结,部分内容进行了简单的处理和归纳,如有谬误,希望大家指出,持续修订更新中。
修订历史版本见:https://github.com/hustlei/AI_Learning_MindMap
未经允许请勿转载。