Python Matplotlib 多图显示 subplot:从组合布局到嵌套图形的全面解析

Python Matplotlib 多图显示 subplot:从组合布局到嵌套图形的全面解析

本篇文章详解了 Matplotlib 的多图合并显示的多种方法,包括基础的子图组合、栅格布局、多图嵌套以及孪生坐标系的应用。通过详尽的代码示例与运行结果,读者可以快速掌握如何在一个窗口中展示多个图形。文章涵盖了均匀子图排列、跨行跨列布局的创建技巧,以及如何通过 subplot2gridGridSpec 实现更加精细的栅格图布局。此外,文章还介绍了如何嵌套多个图形,实现主图与子图的组合效果,并通过孪生坐标系为同一图形添加多个 Y 轴以展示不同维度的数据。丰富的注释与图例为每种方法提供了直观的解析,是学习 Matplotlib 多图显示的实用指南。不论是数据科学初学者,还是需要制作复杂图表的开发者,都能从中获益匪浅。

文章目录

  • Python Matplotlib 多图显示 subplot:从组合布局到嵌套图形的全面解析
  • 一 子图组合 subplot
  • 1 均匀图
  • 运行结果
  • 2 跨列图
  • 运行结果
  • 二 栅格布局 grid
  • 1 使用 `subplot2grid` 创建子图布局
  • 运行结果
  • 2 通过 `GridSpec` 创建子图布局
  • 运行结果
  • 3 使用 `plt.subplots` 创建子图网格
  • 代码释义
  • 运行结果
  • 三 多图嵌套 plot_in_plot
  • 运行结果
  • 四 孪生坐标系 twinx
  • 五 完整代码示例
  • 六 源码地址
  • 七 参考
  • 一 子图组合 subplot

    1 均匀图
    def subplot01():
        # 创建一个图形窗口
        plt.figure()
        # 在2x2的网格中创建第1个子图位置
        plt.subplot(2, 2, 1)
        # 在第1个子图中绘制一条线,从(0,0)到(1,1)
        plt.plot([0, 1], [0, 1])
    
        # 在2x2的网格中创建第2个子图位置
        plt.subplot(2, 2, 2)
        # 在第2个子图中绘制一条线,从(0,0)到(1,2)
        plt.plot([0, 1], [0, 2])
    
        # 在2x2的网格中创建第3个子图位置,使用另一种指定方式223
        plt.subplot(223)
        # 在第3个子图中绘制一条线,从(0,0)到(1,3)
        plt.plot([0, 1], [0, 3])
    
        # 在2x2的网格中创建第4个子图位置,使用另一种指定方式224
        plt.subplot(224)
        # 在第4个子图中绘制一条线,从(0,0)到(1,4)
        plt.plot([0, 1], [0, 4])
    
        # 显示图形窗口
        plt.show()
    
    运行结果

    2 跨列图
    def subplot02():
        # 在2行1列的网格中创建第1个子图位置,此子图占据第一行的全部
        plt.subplot(2, 1, 1)
        # 在第1个子图中绘制一条线,从(0,0)到(1,1)
        plt.plot([0, 1], [0, 1])
    
        # 在2行3列的网格中创建第4个子图位置,这里的子图位于第二行的第一个位置
        plt.subplot(2, 3, 4)
        # 在第2个子图中绘制一条线,从(0,0)到(1,2)
        plt.plot([0, 1], [0, 2])
    
        # 使用简写方式235,等同于在2行3列的网格中指定第5个子图,即第二行的第二个位置
        plt.subplot(235)
        # 在第3个子图中绘制一条线,从(0,0)到(1,3)
        plt.plot([0, 1], [0, 3])
    
        # 使用简写方式236,等同于在2行3列的网格中指定第6个子图,即第二行的第三个位置
        plt.subplot(236)
        # 在第4个子图中绘制一条线,从(0,0)到(1,4)
        plt.plot([0, 1], [0, 4])
    
        # 显示图形窗口
        plt.show()
    
    运行结果

    二 栅格布局 grid

    1 使用 subplot2grid 创建子图布局
    def subplot_grid_01():
        # 创建一个新的图形窗口
        plt.figure()
        # 创建一个子图,占据3行3列网格的第0行所有3列
        ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
        ax1.plot([1, 2], [1, 2])  # 在ax1中绘制线图
        ax1.set_title('ax1_title')  # 设置ax1的标题
    
        # 创建一个子图,占据第1行的前2列
        ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)
        # 创建一个子图,从第1行第3列开始,纵向跨越2行
        ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
        # 创建一个子图,在第2行第1列
        ax4 = plt.subplot2grid((3, 3), (2, 0))
        # 创建一个子图,在第2行第2列
        ax5 = plt.subplot2grid((3, 3), (2, 1))
    
        # 在ax4中绘制散点图
        ax4.scatter([1, 2], [2, 2])
        # 设置ax4的x轴标签
        ax4.set_xlabel('ax4_x')
        # 设置ax4的y轴标签
        ax4.set_ylabel('ax4_y')
    
        # 显示图形窗口
        plt.show()
    
    运行结果

    2 通过 GridSpec 创建子图布局
    def subplot_grid_spec():
        # 创建一个图形窗口
        plt.figure()
        # 初始化一个网格布局,3行3列
        gs = gridspec.GridSpec(3, 3)
    
        # 创建一个子图,占据第一行的所有3列
        plt.subplot(gs[0, :])
        # 创建一个子图,占据第二行的前两列
        plt.subplot(gs[1, :2])
        # 创建一个子图,占据第二行的第三列,并延伸至第三行
        plt.subplot(gs[1:, 2])
        # 创建一个子图,位于最后一行的第一列
        plt.subplot(gs[-1, 0])
        # 创建一个子图,位于最后一行的第二列
        plt.subplot(gs[-1, -2])
    
        # 显示图形
        plt.show()
    
    运行结果

    3 使用 plt.subplots 创建子图网格
    def subplot_s():
        # 创建一个2行2列的子图网格,并共享x轴和y轴
        # 返回的f是整个图形对象,((ax11, ax12), (ax13, ax14))是子图的坐标轴对象
        f, ((ax11, ax12), (ax13, ax14)) = plt.subplots(2, 2, sharex=True, sharey=True)
    
        # 在第一个子图(ax11)中绘制散点图
        ax11.scatter([1, 2], [1, 2])
    
        # 调整子图之间的间距,以防止重叠
        plt.tight_layout()
    
        # 显示图形
        plt.show()
    
    代码释义
  • plt.subplots(2, 2, sharex=True, sharey=True)

  • 2, 2:指定子图网格为2行2列,总共有4个子图。

  • sharex=Truesharey=True:表示子图之间共享x轴和y轴的刻度,这样可以确保所有子图的刻度范围一致。

  • 返回值:

  • f 是整个图形对象,可以用来设置整体图形的属性。
  • ((ax11, ax12), (ax13, ax14)) 是一个包含4个子图坐标轴的二维元组,分别对应每个子图。
  • ax11.scatter([1, 2], [1, 2])

  • 在第一个子图 ax11 中绘制散点图,点的坐标为 (1, 1)(2, 2)

  • plt.tight_layout()

  • 自动调整子图之间的间距,以避免子图之间出现重叠,保证整体布局更美观。

  • 该函数绘制了一个包含4个子图的网格,每个子图共享相同的x轴和y轴刻度。只有第一个子图 ax11 中绘制了散点图,其余子图没有内容。如果需要在其他子图中添加内容,可以调用 ax12, ax13, ax14 来绘制。

    运行结果

    三 多图嵌套 plot_in_plot

    def plot_in_plot():
        # 初始化figure对象
        fig = plt.figure()
    
        # 创建基础数据
        x = [1, 2, 3, 4, 5, 6, 7]
        y = [1, 3, 4, 2, 5, 8, 6]
    
        # 设置大图的坐标轴位置
        left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
        ax1 = fig.add_axes([left, bottom, width, height])  # 添加大图
        ax1.plot(x, y, 'r')  # 大图中绘制红色线条
        ax1.set_xlabel('x')  # 设置x轴标签
        ax1.set_ylabel('y')  # 设置y轴标签
        ax1.set_title('title')  # 设置大图标题
    
        # 在大图中嵌入小图1:左上角
        left, bottom, width, height = 0.2, 0.6, 0.25, 0.25
        ax2 = fig.add_axes([left, bottom, width, height])  # 添加小图1
        ax2.plot(y, x, 'b')  # 小图1中绘制蓝色线条
        ax2.set_xlabel('x')  # 设置小图1的x轴标签
        ax2.set_ylabel('y')  # 设置小图1的y轴标签
        ax2.set_title('title inside 1')  # 设置小图1标题
    
        # 在大图中嵌入小图2:右下角
        plt.axes([0.6, 0.2, 0.25, 0.25])  # 添加小图2
        plt.plot(y[::-1], x, 'g')  # 小图2中绘制绿色线条,y数据逆序处理
        plt.xlabel('x')  # 设置小图2的x轴标签
        plt.ylabel('y')  # 设置小图2的y轴标签
        plt.title('title inside 2')  # 设置小图2标题
    
        # 显示最终图形
        plt.show()
    
    运行结果

    四 孪生坐标系 twinx

    def twinx():
        # 创建x轴的数据,从0到10,步长0.1
        x = np.arange(0, 10, 0.1)
        # 创建y1数据,y1是x的平方乘以0.05
        y1 = 0.05 * x ** 2
        # 创建y2数据,y2是y1的相反数
        y2 = -1 * y1
    
        # 创建一个图和一个子图轴ax1
        _, ax1 = plt.subplots()
        # 创建第二个y轴ax2,共享ax1的x轴
        ax2 = ax1.twinx()
    
        # 在ax1上绘制x和y1的关系,线条为绿色实线
        ax1.plot(x, y1, 'g-')  # green, solid line
        # 设置ax1的x轴和y轴标签
        ax1.set_xlabel('X data')
        ax1.set_ylabel('Y1 data', color='g')
    
        # 在ax2上绘制x和y2的关系,线条为蓝色实线
        ax2.plot(x, y2, 'b-')  # blue
        # 设置ax2的y轴标签,并设置文字颜色为蓝色
        ax2.set_ylabel('Y2 data', color='b')
    
        # 显示图表
        plt.show()
    

    运行结果

    五 完整代码示例

    # This is a sample Python script.
    
    # Press ⌃R to execute it or replace it with your code.
    # Press Double ⇧ to search everywhere for classes, files, tool windows, actions, and settings.
    import matplotlib.pyplot as plt
    import matplotlib.gridspec as gridspec
    import numpy as np
    
    
    def print_hi(name):
        # Use a breakpoint in the code line below to debug your script.
        print(f'Hi, {name}')  # Press ⌘F8 to toggle the breakpoint.
    
    
    def subplot01():
        # 创建一个图形窗口
        plt.figure()
        # 在2x2的网格中创建第1个子图位置
        plt.subplot(2, 2, 1)
        # 在第1个子图中绘制一条线,从(0,0)到(1,1)
        plt.plot([0, 1], [0, 1])
    
        # 在2x2的网格中创建第2个子图位置
        plt.subplot(2, 2, 2)
        # 在第2个子图中绘制一条线,从(0,0)到(1,2)
        plt.plot([0, 1], [0, 2])
    
        # 在2x2的网格中创建第3个子图位置,使用另一种指定方式223
        plt.subplot(223)
        # 在第3个子图中绘制一条线,从(0,0)到(1,3)
        plt.plot([0, 1], [0, 3])
    
        # 在2x2的网格中创建第4个子图位置,使用另一种指定方式224
        plt.subplot(224)
        # 在第4个子图中绘制一条线,从(0,0)到(1,4)
        plt.plot([0, 1], [0, 4])
    
        # 显示图形窗口
        plt.show()
    
    
    def subplot02():
        # 在2行1列的网格中创建第1个子图位置,此子图占据第一行的全部
        plt.subplot(2, 1, 1)
        # 在第1个子图中绘制一条线,从(0,0)到(1,1)
        plt.plot([0, 1], [0, 1])
    
        # 在2行3列的网格中创建第4个子图位置,这里的子图位于第二行的第一个位置
        plt.subplot(2, 3, 4)
        # 在第2个子图中绘制一条线,从(0,0)到(1,2)
        plt.plot([0, 1], [0, 2])
    
        # 使用简写方式235,等同于在2行3列的网格中指定第5个子图,即第二行的第二个位置
        plt.subplot(235)
        # 在第3个子图中绘制一条线,从(0,0)到(1,3)
        plt.plot([0, 1], [0, 3])
    
        # 使用简写方式236,等同于在2行3列的网格中指定第6个子图,即第二行的第三个位置
        plt.subplot(236)
        # 在第4个子图中绘制一条线,从(0,0)到(1,4)
        plt.plot([0, 1], [0, 4])
    
        # 显示图形窗口
        plt.show()
    
    
    def subplot_grid_01():
        # 创建一个新的图形窗口
        plt.figure()
        # 创建一个子图,占据3行3列网格的第0行所有3列
        ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3)
        ax1.plot([1, 2], [1, 2])  # 在ax1中绘制线图
        ax1.set_title('ax1_title')  # 设置ax1的标题
    
        # 创建一个子图,占据第1行的前2列
        ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2)
        # 创建一个子图,从第1行第3列开始,纵向跨越2行
        ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2)
        # 创建一个子图,在第2行第1列
        ax4 = plt.subplot2grid((3, 3), (2, 0))
        # 创建一个子图,在第2行第2列
        ax5 = plt.subplot2grid((3, 3), (2, 1))
    
        # 在ax4中绘制散点图
        ax4.scatter([1, 2], [2, 2])
        # 设置ax4的x轴标签
        ax4.set_xlabel('ax4_x')
        # 设置ax4的y轴标签
        ax4.set_ylabel('ax4_y')
    
        # 显示图形窗口
        plt.show()
    
    
    def subplot_grid_spec():
        # 创建一个图形窗口
        plt.figure()
        # 初始化一个网格布局,3行3列
        gs = gridspec.GridSpec(3, 3)
    
        # 创建一个子图,占据第一行的所有3列
        plt.subplot(gs[0, :])
        # 创建一个子图,占据第二行的前两列
        plt.subplot(gs[1, :2])
        # 创建一个子图,占据第二行的第三列,并延伸至第三行
        plt.subplot(gs[1:, 2])
        # 创建一个子图,位于最后一行的第一列
        plt.subplot(gs[-1, 0])
        # 创建一个子图,位于最后一行的第二列
        plt.subplot(gs[-1, -2])
    
        # 显示图形
        plt.show()
    
    
    def subplot_s():
        # 创建一个2行2列的子图网格,并共享x轴和y轴
        # 返回的f是整个图形对象,((ax11, ax12), (ax13, ax14))是子图的坐标轴对象
        f, ((ax11, ax12), (ax13, ax14)) = plt.subplots(2, 2, sharex=True, sharey=True)
    
        # 在第一个子图(ax11)中绘制散点图
        ax11.scatter([1, 2], [1, 2])
    
        # 调整子图之间的间距,以防止重叠
        plt.tight_layout()
    
        # 显示图形
        plt.show()
    
    
    def plot_in_plot():
        # 初始化figure对象
        fig = plt.figure()
    
        # 创建基础数据
        x = [1, 2, 3, 4, 5, 6, 7]
        y = [1, 3, 4, 2, 5, 8, 6]
    
        # 设置大图的坐标轴位置
        left, bottom, width, height = 0.1, 0.1, 0.8, 0.8
        ax1 = fig.add_axes([left, bottom, width, height])  # 添加大图
        ax1.plot(x, y, 'r')  # 大图中绘制红色线条
        ax1.set_xlabel('x')  # 设置x轴标签
        ax1.set_ylabel('y')  # 设置y轴标签
        ax1.set_title('title')  # 设置大图标题
    
        # 在大图中嵌入小图1:左上角
        left, bottom, width, height = 0.2, 0.6, 0.25, 0.25
        ax2 = fig.add_axes([left, bottom, width, height])  # 添加小图1
        ax2.plot(y, x, 'b')  # 小图1中绘制蓝色线条
        ax2.set_xlabel('x')  # 设置小图1的x轴标签
        ax2.set_ylabel('y')  # 设置小图1的y轴标签
        ax2.set_title('title inside 1')  # 设置小图1标题
    
        # 在大图中嵌入小图2:右下角
        plt.axes([0.6, 0.2, 0.25, 0.25])  # 添加小图2
        plt.plot(y[::-1], x, 'g')  # 小图2中绘制绿色线条,y数据逆序处理
        plt.xlabel('x')  # 设置小图2的x轴标签
        plt.ylabel('y')  # 设置小图2的y轴标签
        plt.title('title inside 2')  # 设置小图2标题
    
        # 显示最终图形
        plt.show()
    
    
    def twinx():
        # 创建x轴的数据,从0到10,步长0.1
        x = np.arange(0, 10, 0.1)
        # 创建y1数据,y1是x的平方乘以0.05
        y1 = 0.05 * x ** 2
        # 创建y2数据,y2是y1的相反数
        y2 = -1 * y1
    
        # 创建一个图和一个子图轴ax1
        _, ax1 = plt.subplots()
        # 创建第二个y轴ax2,共享ax1的x轴
        ax2 = ax1.twinx()
    
        # 在ax1上绘制x和y1的关系,线条为绿色实线
        ax1.plot(x, y1, 'g-')  # green, solid line
        # 设置ax1的x轴和y轴标签
        ax1.set_xlabel('X data')
        ax1.set_ylabel('Y1 data', color='g')
    
        # 在ax2上绘制x和y2的关系,线条为蓝色实线
        ax2.plot(x, y2, 'b-')  # blue
        # 设置ax2的y轴标签,并设置文字颜色为蓝色
        ax2.set_ylabel('Y2 data', color='b')
    
        # 显示图表
        plt.show()
    
    
    # Press the green button in the gutter to run the script.
    if __name__ == '__main__':
        print_hi('多图合并显示')
        # Subplot 多合一显示,均匀图中图
        subplot01()
        # Subplot 多合一显示,不均匀图中图
        subplot02()
    
        # Subplot 分格显示
        subplot_grid_01()
        subplot_grid_spec()
        subplot_s()
    
        # 图中图 plot in plot
        plot_in_plot()
    
        # 次坐标轴 twinx
        twinx()
    
    # See PyCharm help at https://www.jetbrains.com/help/pycharm/
    

    复制粘贴并覆盖到你的 main.py 中运行,运行结果如下。

    Hi, 多图合并显示
    

    六 源码地址

    代码地址:

    国内看 Gitee 之 matplotlib/多图合并显示.py

    国外看 GitHub 之 matplotlib/多图合并显示.py

    七 参考

    [1] Matplotlib 官网

    [2] 莫烦 python

    作者:敲代码不忘补水

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python Matplotlib 多图显示 subplot:从组合布局到嵌套图形的全面解析

    发表回复