• 【PyQt】在PyQt5的界面上集成matplotlib绘制的图像


    0 前期教程

    1 概述

      在上面的前期教程中,介绍了在PyQt5中如何绘制曲线,是使用PyQt5的一些第三方扩展包来实现的,但是提到python中的画图,matplotlib才是最受欢迎的工具,因此,在PyQt5界面中集成一个matplotlib绘制的图非常有用。

    2 matplotlib

      在开始之前,我们先来系统地复习一下matplotlib这个库。学习一个库,首先要参考的肯定是官网——https://matplotlib.org/stable/

      如果使用这个库较多,强烈建议完整看一遍Quick start guide,这样会对这个库有一个整体的认识,也更利于理解他人的代码。以下内容也基本摘自该教程。

    2.1 库导入

      首先是库导入,一般采用以下这种方式:

    import matplotlib.pyplot as plt
    import numpy as np
    
    import matplotlib as mpl
    
    • 1
    • 2
    • 3
    • 4

    注意:在一些比较老的代码中,可能会看到import matplotlib.pylab as plt这样的代码,这个pylab是已经被弃用的库。

    2.2 图片的各个部分解释

      在绘制一些相对复杂的图时,首先要理解一张图片中各个部分分别对应什么,这样更便于使用对应的函数以及查找相关的资料。以下这张图也摘自官网,详细介绍了一张图的各个部分及其对应的类和函数,非常详细,值得反复阅读。

    在这里插入图片描述
    注意,这里的ax来自以下代码:

    fig, ax = plt.subplots()  # Create a figure containing a single axes.
    ax.plot([1, 2, 3, 4], [1, 4, 2, 3])  # Plot some data on the axes.
    
    • 1
    • 2

    2.3 代码风格

      在绘制图像方面,主要有两种常用的类型。分为显式接口(explicit interfaces)隐式接口(implicit interfaces),其中,所谓显式接口是使用面向对象的方式(object-oriented (OO) style);而隐式接口则是使用pyplot这个模块隐式地创建和管理图像和坐标轴等对象,即只使用pyplot里面的函数即可。

    • 显式接口

      x = np.linspace(0, 2, 100)  # Sample data.
      
      # Note that even in the OO-style, we use `.pyplot.figure` to create the Figure.
      fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained')
      ax.plot(x, x, label='linear')  # Plot some data on the axes.
      ax.plot(x, x**2, label='quadratic')  # Plot more data on the axes...
      ax.plot(x, x**3, label='cubic')  # ... and some more.
      ax.set_xlabel('x label')  # Add an x-label to the axes.
      ax.set_ylabel('y label')  # Add a y-label to the axes.
      ax.set_title("Simple Plot")  # Add a title to the axes.
      ax.legend()  # Add a legend.
      plt.show()   # display
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12

    在这里插入图片描述

    • 隐式接口

      x = np.linspace(0, 2, 100)  # Sample data.
      
      plt.figure(figsize=(5, 2.7), layout='constrained')
      plt.plot(x, x, label='linear')  # Plot some data on the (implicit) axes.
      plt.plot(x, x**2, label='quadratic')  # etc.
      plt.plot(x, x**3, label='cubic')
      plt.xlabel('x label')
      plt.ylabel('y label')
      plt.title("Simple Plot")
      plt.legend()
      plt.show()   # display
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

    在这里插入图片描述

    图片绘制方面,还有更丰富的一些设置,如设置线的样式(styling),或者在图片上增加标注(labelling)等,具体建议参考官网的教程。

    2.4 后端

      所谓后端(backends),和网页的前端后端我认为概念上类似,但又有点区别,简而言之,对画图而言,前端即是画什么样的图,而后端则是在哪画图,即显示在哪

      根据官网的教程,matplotlib内部有多种后端可供选择,如Qt,GTK,wxWidgets,OSX,Tk等,分别对应的代码为:qtagg, GTK4Agg, GTK3Agg, wxAgg, macosx, TkAgg。此外,它还支持非内置的后端。
      指定后端的方式有三种:

    • 在 matplotlibrc 文件中设置 rcParams["backend"],如backend : qtagg
    • 在shell中设置 MPLBACKEND 环境变量,如在Windows端执行这个代码 set MPLBACKEND=qtagg
    • 在python脚本中增加代码:import matplotlib matplotlib.use('qtagg')

      很显然,在Windows上集成图像到Qt界面上最简单的办法就是第三种。

    3 集成matplotlib图像到pyqt界面中

    3.1 使用到的模块

      在大部分的教程中,一般都会有这样几行代码:

    import matplotlib as mpl
    mpl.use('Qt5Agg')
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.figure import Figure
    
    • 1
    • 2
    • 3
    • 4

    其中,前两行是指定后端,第三行导入的FigureCanvasQTAgg实际上也是一个Qt的控件,也可以像一般的控件一样添加到Qt的窗口中,它相当于是一个画布,并不直接画图;而第四行导入的figure就是图像本身了,用于画图的各种操作。

    3.2 理解Qt Designer中的“控件提升”

      控件提升操作在上面的前期教程中也有使用过,但是当时并没有对此理解很深入,只知道这样做而已。经过对比转换得到的py代码,发现所谓的控件提升,其实就是替换,即将放置的控件替换为其他的Qt控件,比如之前的QChartView和这里的FigureCanvasQTAgg,都是Qt控件,所以可以直接替换。原控件的作用主要设置布局和大小等外部特性。

      可以自行尝试一下,拖动一个widget到窗口,然后将其提升,内容可以随便写,再转换成python代码,观察填写的内容在实际代码中的体现。
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    从上面的实践可以看出,实际上被提升的控件是什么类型并不重要,只要可以提升就行。常用的有Qwidget,QFrame等。

    3.3 界面与逻辑分离的思路

      之所以要介绍上述的控件提升,就是为在集成matplotlib图像到pyqt界面过程中也保持界面和逻辑分离的状态
      为了实现这一目标,首先建立一个文件,命名为FigureCanvas.py(可以随便取),写入以下代码:

    import matplotlib as mpl
    mpl.use('Qt5Agg')
    from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
    from matplotlib.figure import Figure
    
    class MyFigure(FigureCanvas):
        def __init__(self, parent=None):
            self.fig = Figure()
            super().__init__(self.fig)
            self.axes = self.fig.add_subplot(111)
    
        def plot(self, *args, **kwargs):
            self.axes.clear()                 # 清除之前的图像
            self.axes.plot(*args, **kwargs)   # 画图
            self.fig.canvas.draw()            # 刷新画布
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    可以看到,内容非常简单,就是在前面介绍的头文件基础上,新建了一个类而已,这个类除了初始化函数外也就只有一个刷新图像界面的函数。
      然后在Qt Designer中添加一个widget控件,再把它提升一下:由于导入关系是from FigureCanvas import MyFigure,所以类名称为MyFigure,头文件为FigureCanvas

      最后,就是再新建一个py文件编写逻辑和界面显示等内容了,这里可以参考前期教程,此处不再赘述。

    3.4 扩展

      在查找资料过程中,还找到一个方法有点不同的教程,它是使用graphicView控件来实现的,是基于该控件自带的一些函数来实现的。而且也做到了界面和逻辑分离,值得记录一下:链接

  • 相关阅读:
    pytorch深度学习实战lesson10
    C语言错题总结
    使用PHP实现对称加密和解密过程,真的是太简单了!
    C# 实现迷宫游戏
    代码随想录算法训练营第五十天 |123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV
    springcloudalibaba架构(7):Sentinel授权规则和系统规则
    期货的含义及交易特点
    sCrypt 合约中的椭圆曲线算法:第一部分
    从意义中恢复,而不是从数据包中恢复
    FANUC机器人_通过ROBOGUIDE从零开始做一个离线仿真项目(2)
  • 原文地址:https://blog.csdn.net/ZHOU_YONG915/article/details/135826622