Python3.10 Matplotlib.pyplot GridSpec 完整详解 + 实战示例

一、GridSpec 是什么
matplotlib.gridspec.GridSpec 是 Matplotlib 中高级画布布局工具,用来替代简单的 plt.subplots(),实现不规则子图布局:
子图可跨多行、多列;
自定义行列宽高比例、子图间距;
支持嵌套网格(GridSpec 里再套 GridSpec);
配合 plt.figure() 使用,区别于固定均分的 subplot(nrows,ncols,idx)。
导入依赖

点击查看代码
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
import numpy as np

二、核心参数说明

点击查看代码
GridSpec(nrows, ncols, figure=None,
         width_ratios=None,   # 各列宽度比例 [1,2,1] 三列宽1:2:1
         height_ratios=None,  # 各行高度比例
         wspace=0.2,          # 子图水平间距(列间隙)
         hspace=0.2,          # 子图垂直间距(行间隙)
         left=None, right=None, top=None, bottom=None) # 画布边距

关键取值规则
切片选取子图:gs[a:b, c:d]
行切片 a:b:占据第 a 行到 b-1 行
列切片 c:d:占据第 c 列到 d-1 列
单个格子:gs[i,j] 第 i 行第 j 列
跨整行:gs[i, :];跨整列:gs[:, j]
三、示例 1:基础不规则布局(最常用)
需求:2 行 3 列网格
左上子图:占 1 行 1 列 gs[0,0]
顶部大图:跨第 0 行 1、2 列 gs[0,1:]
底部整张图:跨全部 3 列 gs[1,:]

点击查看代码
# 1. 创建画布
fig = plt.figure(figsize=(10, 6), dpi=100)

# 2. 定义2行3列网格,自定义行列间距
gs = GridSpec(nrows=2, ncols=3, figure=fig, hspace=0.3, wspace=0.2)

# 3. 分配子图位置
ax1 = fig.add_subplot(gs[0, 0])        # 第0行第0列
ax2 = fig.add_subplot(gs[0, 1:])       # 第0行,第1、2列(跨两列)
ax3 = fig.add_subplot(gs[1, :])        # 第1行全部三列(跨三列)

# 绘图测试数据
x = np.linspace(0, 2*np.pi, 100)
ax1.plot(x, np.sin(x), c="red")
ax1.set_title("ax1: 单格子图")

ax2.plot(x, np.cos(x), c="green")
ax2.set_title("ax2: 跨2列子图")

ax3.plot(x, np.tan(x), c="blue")
ax3.set_title("ax3: 跨全部3列")

plt.show()

四、示例 2:自定义行列宽高比例 width_ratios /height_ratios
需求:3 行 2 列
行高比例:1 : 3 : 1(中间行高度是上下 3 倍)
列宽比例:2 : 1(左列宽度是右列 2 倍)
右上角子图跨前两行:gs[0:2, 1]

点击查看代码
fig = plt.figure(figsize=(8, 7))
# 3行2列,设置宽高比例,间隙
gs = GridSpec(
    nrows=3, ncols=2,
    width_ratios=[2, 1],    # 列宽比
    height_ratios=[1, 3, 1],# 行高比
    wspace=0.25, hspace=0.3
)

ax1 = fig.add_subplot(gs[:, 0])   # 左列,全部3行
ax2 = fig.add_subplot(gs[0:2, 1]) # 右列,0、1两行(跨两行)
ax3 = fig.add_subplot(gs[2, 1])   # 右列,第2行单独一格

# 绘图
x = np.linspace(-5,5,200)
ax1.hist(np.random.normal(0,1,1000), bins=30, color="orange")
ax1.set_title("左列占全部3行")

ax2.scatter(x, np.sin(x), c="purple", s=8)
ax2.set_title("右列跨前2行")

ax3.plot(x, x**2, c="black")
ax3.set_title("右下角单格")

plt.show()
五、示例 3:GridSpec 嵌套(复杂多分区画布) 超大画布拆分:外层 1 行 2 列,左右两大部分,每部分内部再单独创建 GridSpec,适合多模块复杂报表。
点击查看代码
fig = plt.figure(figsize=(12, 5))
# 外层网格:1行2列
gs_main = GridSpec(1, 2, figure=fig, wspace=0.3)

# ========== 左侧区域:内部2行2列小网格 ==========
gs_left = GridSpecFromSubplotSpec(
    nrows=2, ncols=2,
    subplot_spec=gs_main[0],  # 绑定外层第0列
    hspace=0.2, wspace=0.2
)
ax_l1 = fig.add_subplot(gs_left[0,0])
ax_l2 = fig.add_subplot(gs_left[0,1])
ax_l3 = fig.add_subplot(gs_left[1,:]) # 跨两列

# ========== 右侧区域:内部3行1列 ==========
gs_right = GridSpecFromSubplotSpec(
    nrows=3, ncols=1,
    subplot_spec=gs_main[1],  # 绑定外层第1列
    hspace=0.3
)
ax_r1 = fig.add_subplot(gs_right[0,0])
ax_r2 = fig.add_subplot(gs_right[1,0])
ax_r3 = fig.add_subplot(gs_right[2,0])

# 填充测试图
data = np.random.randn(100)
ax_l1.plot(data)
ax_l2.hist(data)
ax_l3.scatter(range(len(data)), data)
ax_r1.boxplot(data)
ax_r2.plot(np.cumsum(data))
ax_r3.hist(np.abs(data))

plt.suptitle("GridSpec 嵌套布局", fontsize=14)
plt.show()
补充:GridSpecFromSubplotSpec 专门用于嵌套网格,接收父网格区域 subplot_spec。 六、示例 4:手动控制画布边距 left/right/top/bottom 默认子图会留大量空白,用 GridSpec 全局统一控制边距:
点击查看代码
fig = plt.figure(figsize=(8,4))
# left:左边界,right:右边界,bottom:底部,top:顶部 取值0~1
gs = GridSpec(
    1, 2, figure=fig,
    left=0.05, right=0.95,
    bottom=0.1, top=0.9,
    wspace=0.1
)
ax1 = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1])

ax1.plot([1,2,3], [2,1,3])
ax2.bar(["A","B","C"], [3,1,4])
plt.show()

七、GridSpec 与 subplots () 的区别
表格
特性 plt.subplots() GridSpec
布局 只能均分网格,子图不能跨行跨列 支持任意跨行、跨列、不规则布局
宽高比例 只能整体统一,无法单独行列设置 width_ratios /height_ratios 自由定义
嵌套 不支持嵌套网格 支持多层嵌套,复杂报表首选
间距 统一 wspace/hspace,灵活性差 每个网格可单独设置间距、边距
八、常见踩坑点(Python3.10 通用)
切片越界报错:网格 nrows=2,行索引只能取 0/1,切片 0:2 合法,0:3 报错;
多子图重叠:忘记设置 wspace/hspace,子图坐标轴、标题互相遮挡;
嵌套忘记导入 GridSpecFromSubplotSpec:嵌套布局必须用该类,不能直接新建 GridSpec;
figure 参数遗漏:GridSpec(..., figure=fig) 必须绑定画布,否则绘图无显示;
版本兼容:Python3.10 配套 Matplotlib 3.4+ 完整支持 GridSpec 全部 API,无语法兼容问题。
九、完整可运行整合代码(复制直接跑)

点击查看代码
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec
import numpy as np

# 示例1:基础跨行跨列布局
def demo1_basic():
    fig = plt.figure(figsize=(10, 6), dpi=100)
    gs = GridSpec(2, 3, figure=fig, hspace=0.3, wspace=0.2)
    ax1 = fig.add_subplot(gs[0, 0])
    ax2 = fig.add_subplot(gs[0, 1:])
    ax3 = fig.add_subplot(gs[1, :])
    x = np.linspace(0, 2*np.pi, 100)
    ax1.plot(x, np.sin(x), c="red")
    ax1.set_title("单格子图")
    ax2.plot(x, np.cos(x), c="green")
    ax2.set_title("跨两列子图")
    ax3.plot(x, np.tan(x), c="blue")
    ax3.set_title("跨全部三列")
    plt.show()

# 示例2:自定义行列比例
def demo2_ratio():
    fig = plt.figure(figsize=(8, 7))
    gs = GridSpec(3, 2, width_ratios=[2,1], height_ratios=[1,3,1], wspace=0.25, hspace=0.3)
    ax1 = fig.add_subplot(gs[:, 0])
    ax2 = fig.add_subplot(gs[0:2, 1])
    ax3 = fig.add_subplot(gs[2, 1])
    x = np.linspace(-5,5,200)
    ax1.hist(np.random.normal(0,1,1000), bins=30, color="orange")
    ax2.scatter(x, np.sin(x), c="purple", s=8)
    ax3.plot(x, x**2, c="black")
    plt.show()

# 示例3:嵌套网格
def demo3_nested():
    fig = plt.figure(figsize=(12, 5))
    gs_main = GridSpec(1, 2, figure=fig, wspace=0.3)
    # 左侧嵌套
    gs_left = GridSpecFromSubplotSpec(2,2, subplot_spec=gs_main[0], hspace=0.2, wspace=0.2)
    fig.add_subplot(gs_left[0,0])
    fig.add_subplot(gs_left[0,1])
    fig.add_subplot(gs_left[1,:])
    # 右侧嵌套
    gs_right = GridSpecFromSubplotSpec(3,1, subplot_spec=gs_main[1], hspace=0.3)
    fig.add_subplot(gs_right[0,0])
    fig.add_subplot(gs_right[1,0])
    fig.add_subplot(gs_right[2,0])
    plt.suptitle("嵌套GridSpec", fontsize=14)
    plt.show()

# 执行示例
if __name__ == "__main__":
    demo1_basic()
    # demo2_ratio()
    # demo3_nested()
posted @ 2026-06-30 22:28  tedtang  阅读(24)  评论(0)    收藏  举报