Matplotlib系列(八):嵌入Python Qt界面

Matplotlib系列目录


文章目录

  • 一、 简介
  • 二、 思维导图
  • 三、 Matplotlib嵌入PyQt界面
  • 1. Matplotlib嵌入GUI基本方法
  • 2. matplotlib界面渲染引擎
  • 2.1 可用的渲染引擎后端
  • 2.2.渲染引擎后端设置
  • 3. 可嵌入GUI的画布
  • 2.3.1 画布及backend模块
  • 2.3.2 qt创建画布的方法
  • 3. Matplotlib嵌入Qt
  • 3.1 Matplotlib嵌入Qt GUI示例
  • 3.2 Matplotlib画布工具栏
  • 4 Matplotlib与GUI互动操作
  • 5 Matplotlib嵌入Qt实例
  • 参考文章

  • 一、 简介

    ‎matplotlib可以很容易嵌入PyQt、GTK、Tk、wxPython以及Web中。这里只介绍嵌入PyQt(PySide)。

    Matplotlib系列将Matplotlib的知识和重点API,编制成思维导图和重点笔记形式,方便记忆和回顾,也方便应用时参考,初学者也可以参考逐步深入学习。

    二、 思维导图

    matplotlib嵌入qt

    三、 Matplotlib嵌入PyQt界面

    1. Matplotlib嵌入GUI基本方法

    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)

    2. matplotlib界面渲染引擎

    matplotlib显示图形实际上通过第三方库作为后端实现的,即调用后端的接口渲染图形。

    matplotlib有多种后端,并且很多后端还有多种可选的UI引擎:

    2.1 可用的渲染引擎后端

    可用的后端简介如下(后端名称不区分大小写)

  • agg(Anti-Grain Geometry):一个C++高保真2D渲染引擎
  • GTK3Agg, GTK4Agg:用agg在GTK Canvas上渲染
  • QtAgg, Qt5Agg:用agg在qt Canvas上渲染
  • TkAgg:用Cairo在Tk Canvas上渲染
  • WXAgg:用agg在wxWidgets Canvas上渲染
  • WebAgg:用html渲染
  • nbAgg(Ipython notebook)
  • cairo:一款开源的2d矢量图形库。Python中用cairocffi或pycairo调用
  • GTK3Cairo,GTK4Cairo::用Cairo在GTK Canvas上渲染
  • QtCairo, Qt4Cairo, Qt5Cairo::用Cairo在Qt Canvas上渲染
  • TkCairo:用Cairo在Tk Canvas上渲染
  • WXCairo:用Cairo在wxWidgets Canvas上渲染
  • WX:用wxWidgets在wxWidgets Canvas上渲染
  • MacOSX:用Cocoa在OSX windows上渲染
  • 用于生成图片及文件的后端
  • pdf
  • pgf
  • ps
  • svg
  • template
  • 以上后端名称都可以用于matplotlib.use函数

    2.2.渲染引擎后端设置

    有三种设置后端引擎的方法:

  • matplotlib.use('agg')
  • rcParams["backend"] = 'agg'
  • MPLBACKEND环境变量
  • 默认后端为’agg’。后端名称字符串不分大小写。

    对于qt。QtAgg和QtCairo后端同时支持Qt5和Qt6。Qt5Agg同时支持PyQt5和Pyside2。
    那么matplotlib会使用pyqt还是pyside作为引擎呢?

  • ‎如果已经加载了任何绑定(PyQt5,PyQt6,PySide2,PySide6),则它将用于Qt后端。‎
  • ‎如果还没有加载了任何绑定,则从QT_API环境变量确定。
  • QT_API环境变量可以设置为PyQt6,PySide6,PyQt5,PySide2,PyQt4或PyQt4v2。不分大小写
  • 如果QT_API环境变量的后端不存在,则自动尝试导入
  • PyQt6
  • PySide6
  • PyQt5
  • PySide2
  • 3. 可嵌入GUI的画布

    2.3.1 画布及backend模块

    Matplotlib还将后端渲染器(renderer)和画布(canvas)分离开来,以实现更灵活的定制功能。画布就是一个GUI的控件,可以直接嵌入GUI中。

    在Matplotlib安装目录的“backends”子目录里是这些后端的模块文件,例如有

  • backend_agg
  • backend_qtagg
  • backend_qt5agg(实际上和backend_qtagg一样,只是为了兼容旧API。)
  • backend_webagg
  • backend_tkagg
  • backend_gtk3agg
  • backend_gtk4agg
  • backend_wxagg
  • backend_cairo
  • backend_qtcairo
  • backend_tkcairo
  • backend_gtk3cairo
  • backend_gtk4cairo
  • backend_wxcairo
  • backend_wx
  • web_backend
  • backend_macosx
  • backend_nbagg
  • backend_mixed
  • 其他
  • backend_pdf
  • backend_pgf
  • backend_ps
  • backend_svg
  • backend_template
  • 2.3.2 qt创建画布的方法

    推荐做法:

    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会有很多功能缺失,甚至不能绘图,需要自行写很多代码
  • 3. Matplotlib嵌入Qt

    3.1 Matplotlib嵌入Qt GUI示例

    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类似的效果。

    3.2 Matplotlib画布工具栏

    每个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())
    

    4 Matplotlib与GUI互动操作

    应用程序与嵌入GUI的matplotlib图形交互实际上就是对Figure、FigureCanvas和NavigationToolbar进行操作。除了绘图函数外,比较有用的函数汇总如下:

  • FigureCanvas
  • canvas.draw():重绘
  • canvas.resize(w,h):设置画布尺寸(像素)
  • canvas.set_cursor(cusor):设置鼠标指针形状
  • canvas.mpl_connect(“key_press_event”,func):绑定事件,返回cid。
  • canvas.mpl_disconnect(cid):解除事件绑定
  • NavigationToolbar
  • toolbar.home():恢复home视图
  • toolbar.back():退回上一个历史视图
  • toolbar.forward():向前到下一个视图
  • toolbar.set_history_buttons():启用、禁用back/forward按钮
  • toolbar.pan():开关移动视图模式
  • toolbar.zoom():开关缩放视图模式
  • toolbar.configure_subplots():打开设置对话框
  • toolbar.save_figure():打开保存对话框
  • toolbar.set_message(“text”):在工具栏的状态显示区显示文本。
  • plt
  • plt.gcf():获取当前figure
  • plt.gca():获取当前axes
  • Figure
  • fig.clf():清空当前figure
  • fig.gca():获取当前axes
  • fig.sca(ax):把ax设置为当前axes
  • fig.delaxes(ax):删除某个axes
  • fig.set_canvas(figurecanvase):为figure设置FigureCanvas
  • fig.show():使用GUI作为backend,显示figure
  • 5 Matplotlib嵌入Qt实例

    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())
    

    参考文章

  • 官方示例
  • 官方教程
  • 预定义图形api

  • Matplotlib系列目录


    个人总结,部分内容进行了简单的处理和归纳,如有谬误,希望大家指出,持续修订更新中。

    修订历史版本见:https://github.com/hustlei/AI_Learning_MindMap

    未经允许请勿转载。

    来源:hustlei

    物联沃分享整理
    物联沃-IOTWORD物联网 » Matplotlib系列(八):嵌入Python Qt界面

    发表评论