当前位置: 首页 > news >正文

Python Matplotlib 布局

Python Matplotlib 布局

flyfish

gridspec.GridSpec 是 Matplotlib 中用于灵活布局子图的工具,特别适合创建非均匀分布的子图(如不同大小、不同比例的子图组合)。相比普通的 plt.subplots()(仅支持规则网格),GridSpec 能实现更复杂的布局,例如“一个大子图+多个小子图”“不同行高/列宽的子图”等。

一、概念

GridSpec 的本质是在画布(Figure)上划分一个“虚拟网格”,通过指定网格的行数、列数以及行高/列宽比例,来精确控制子图的位置和大小。

  • 网格划分:将画布想象成一个网格,GridSpec(nrows, ncols) 定义网格的行数和列数。
  • 子图定位:通过网格的索引(如 gs[0]gs[1:3])指定子图占据的网格区域。
  • 比例控制:通过 height_ratios(行高比例)和 width_ratios(列宽比例)设置不同行/列的相对大小。

二、基础用法:创建非均匀子图

1. 安装与导入
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import gridspec  # 导入GridSpec# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
2. 最简单的GridSpec示例(2行1列,不同高度)
# 创建画布
fig = plt.figure(figsize=(8, 6))  # 宽8英寸,高6英寸# 定义GridSpec:2行1列,行高比例为3:1(第一行高度是第二行的3倍)
gs = gridspec.GridSpec(nrows=2, ncols=1, height_ratios=[3, 1])# 添加子图:通过索引指定子图位置
ax1 = fig.add_subplot(gs[0])  # 第一行(索引0)
ax2 = fig.add_subplot(gs[1])  # 第二行(索引1)# 填充数据
x = np.linspace(0, 10, 100)
ax1.plot(x, np.sin(x), color='blue')
ax1.set_title('主图(占3/4高度)')ax2.plot(x, np.cos(x), color='red')
ax2.set_title('副图(占1/4高度)')# 调整布局避免重叠
plt.tight_layout()
plt.show()

效果:画布被分为上下两部分,上方子图高度是下方的3倍,分别显示正弦和余弦曲线。

三、关键参数:控制行高与列宽

GridSpec 的核心参数是 height_ratios(行高比例)和 width_ratios(列宽比例),用于设置非均匀大小。

示例:3列不同宽度的子图
fig = plt.figure(figsize=(10, 4))# 定义GridSpec:1行3列,列宽比例为1:2:1(中间列宽度是两侧的2倍)
gs = gridspec.GridSpec(nrows=1, ncols=3, width_ratios=[1, 2, 1])# 添加3个子图
ax1 = fig.add_subplot(gs[0])  # 第一列
ax2 = fig.add_subplot(gs[1])  # 第二列(最宽)
ax3 = fig.add_subplot(gs[2])  # 第三列# 填充数据
ax1.bar(['A', 'B'], [3, 5], color='green')
ax1.set_title('列1(宽1份)')ax2.scatter(np.random.rand(50), np.random.rand(50), color='orange')
ax2.set_title('列2(宽2份)')ax3.pie([1, 2, 3], labels=['X', 'Y', 'Z'], autopct='%1.1f%%')
ax3.set_title('列3(宽1份)')plt.tight_layout()
plt.show()

效果:一行三列的子图,中间子图宽度是左右两侧的2倍,适合突出中间内容。

四、进阶:子图跨多行/多列

通过索引切片(如 gs[0:2, 0])可以让子图占据多个行或列,实现“合并单元格”的效果。

示例:复杂布局(大子图+多个小子图)
fig = plt.figure(figsize=(10, 8))# 定义GridSpec:3行3列
# 行高比例:2:1:1(第一行最高)
# 列宽比例:1:2:1(中间列最宽)
gs = gridspec.GridSpec(nrows=3, ncols=3,height_ratios=[2, 1, 1],width_ratios=[1, 2, 1]
)# 子图1:占据第1行的所有3列(0:3表示第0到2列)
ax1 = fig.add_subplot(gs[0, 0:3])
ax1.plot(np.linspace(0, 10, 100), np.sin(np.linspace(0, 10, 100)))
ax1.set_title('第1行(跨3列)')# 子图2:占据第2-3行的第1列(0列)
ax2 = fig.add_subplot(gs[1:3, 0])  # 1:3表示第1-2行(共2行)
ax2.barh(['A', 'B', 'C'], [10, 20, 15], color='purple')
ax2.set_title('第2-3行(第1列)')# 子图3:占据第2行的第2-3列
ax3 = fig.add_subplot(gs[1, 1:3])
ax3.scatter(np.random.rand(30), np.random.rand(30), color='red')
ax3.set_title('第2行(第2-3列)')# 子图4:占据第3行的第2列
ax4 = fig.add_subplot(gs[2, 1])
ax4.pie([40, 60], labels=['成功', '失败'], autopct='%1.1f%%')
ax4.set_title('第3行(第2列)')# 子图5:占据第3行的第3列
ax5 = fig.add_subplot(gs[2, 2])
ax5.hist(np.random.randn(100), bins=10, color='green', alpha=0.7)
ax5.set_title('第3行(第3列)')plt.tight_layout()
plt.show()

效果:整个画布被划分为3x3的虚拟网格,5个子图分别占据不同的网格区域,形成“顶部大标题图+左侧竖图+右侧多张小图”的复杂布局。

五、GridSpec vs plt.subplots:适用场景对比

工具优势适用场景
plt.subplots(nrows, ncols)语法简单,适合规则网格(如2x2、3x1)子图大小相同、排列整齐的情况
gridspec.GridSpec支持非均匀比例、跨行列布局子图大小不同、需要突出重点内容的复杂布局

步骤:

  1. gridspec.GridSpec(nrows, ncols) 定义虚拟网格的行数和列数;
  2. 通过 height_ratioswidth_ratios 控制行高和列宽比例;
  3. 用索引或切片(如 gs[0]gs[1:3, 0])指定子图占据的区域;
  4. fig.add_subplot(gs[...]) 添加子图并绘图。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

# 导入必要库
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import gridspec# 全局配置:解决中文显示与负号问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
np.random.seed(42)  # 固定随机种子,确保结果可复现# -------------------------- 1. 基础:非均匀行高(2行1列,3:1比例)--------------------------
def plot_grid_height_ratio():# 1. 创建画布fig = plt.figure(figsize=(8, 6))  # 宽8,高6英寸# 2. 定义GridSpec:2行1列,行高比例3:1gs = gridspec.GridSpec(nrows=2,  # 行数ncols=1,  # 列数height_ratios=[3, 1],  # 第一行高度是第二行的3倍hspace=0.3  # 行间距(可选,避免子图标题重叠))# 3. 添加子图(通过GridSpec索引定位)ax1 = fig.add_subplot(gs[0])  # 占据第1行(索引0)ax2 = fig.add_subplot(gs[1])  # 占据第2行(索引1)# 4. 填充数据与样式设置x = np.linspace(0, 10, 100)# 子图1:正弦曲线ax1.plot(x, np.sin(x), color='#1f77b4', linewidth=2)ax1.set_title('主图:正弦曲线(占3/4高度)', fontsize=13)ax1.set_xlabel('x轴', fontsize=11)ax1.set_ylabel('sin(x)', fontsize=11)ax1.grid(alpha=0.3)# 子图2:余弦曲线ax2.plot(x, np.cos(x), color='#ff7f0e', linewidth=2)ax2.set_title('副图:余弦曲线(占1/4高度)', fontsize=13)ax2.set_xlabel('x轴', fontsize=11)ax2.set_ylabel('cos(x)', fontsize=11)ax2.grid(alpha=0.3)# 5. 调整布局并保存为JPGplt.tight_layout()plt.savefig('grid_height_ratio.jpg', dpi=300, bbox_inches='tight', format='jpg')plt.close()  # 关闭画布释放内存print("1. 非均匀行高布局图已保存:grid_height_ratio.jpg")# -------------------------- 2. 基础:非均匀列宽(1行3列,1:2:1比例)--------------------------
def plot_grid_width_ratio():# 1. 创建画布fig = plt.figure(figsize=(12, 4))  # 宽12,高4英寸# 2. 定义GridSpec:1行3列,列宽比例1:2:1gs = gridspec.GridSpec(nrows=1,ncols=3,width_ratios=[1, 2, 1],  # 中间列宽度是两侧的2倍wspace=0.3  # 列间距(可选))# 3. 添加子图ax1 = fig.add_subplot(gs[0])  # 第1列ax2 = fig.add_subplot(gs[1])  # 第2列(最宽)ax3 = fig.add_subplot(gs[2])  # 第3列# 4. 填充数据与样式# 子图1:柱状图categories = ['A', 'B', 'C']ax1.bar(categories, [5, 8, 3], color='#2ca02c', alpha=0.8)ax1.set_title('列1:类别对比(1份宽)', fontsize=12)ax1.set_ylabel('数值', fontsize=10)ax1.grid(axis='y', alpha=0.3)# 子图2:散点图(突出显示)x_scatter = np.random.randn(100)y_scatter = 2 * x_scatter + np.random.randn(100) * 0.5ax2.scatter(x_scatter, y_scatter, color='#d62728', alpha=0.6)ax2.set_title('列2:相关性散点图(2份宽)', fontsize=12)ax2.set_xlabel('x', fontsize=10)ax2.set_ylabel('y', fontsize=10)ax2.grid(alpha=0.3)# 子图3:饼图pie_data = [30, 50, 20]ax3.pie(pie_data, labels=['甲', '乙', '丙'], autopct='%1.1f%%', colors=['#9467bd', '#8c564b', '#e377c2'])ax3.set_title('列3:占比分布(1份宽)', fontsize=12)ax3.axis('equal')  # 确保饼图为圆形# 5. 保存图片plt.tight_layout()plt.savefig('grid_width_ratio.jpg', dpi=300, bbox_inches='tight', format='jpg')plt.close()print("2. 非均匀列宽布局图已保存:grid_width_ratio.jpg")# -------------------------- 3. 进阶:子图跨多行多列(3x3网格复杂布局)--------------------------
def plot_grid_span_rows_cols():# 1. 创建画布fig = plt.figure(figsize=(12, 10))  # 宽12,高10英寸(适合复杂布局)# 2. 定义GridSpec:3行3列,行高比例2:1:1,列宽比例1:2:1gs = gridspec.GridSpec(nrows=3,ncols=3,height_ratios=[2, 1, 1],  # 第1行最高,占2份width_ratios=[1, 2, 1],   # 第2列最宽,占2份hspace=0.3,  # 行间距wspace=0.3   # 列间距)# 3. 添加子图(通过切片实现跨行列)# 子图1:跨第1行所有3列(行索引0,列索引0-2)ax1 = fig.add_subplot(gs[0, :])  # ":" 表示所有列# 子图2:跨第2-3行的第1列(行索引1-2,列索引0)ax2 = fig.add_subplot(gs[1:, 0])  # "1:" 表示第1行及以下# 子图3:跨第2行的第2-3列(行索引1,列索引1-2)ax3 = fig.add_subplot(gs[1, 1:])# 子图4:第3行第2列(行索引2,列索引1)ax4 = fig.add_subplot(gs[2, 1])# 子图5:第3行第3列(行索引2,列索引2)ax5 = fig.add_subplot(gs[2, 2])# 4. 填充数据与样式x = np.linspace(0, 10, 100)# 子图1:顶部大标题图(折线图)ax1.plot(x, np.sin(x), label='sin(x)', color='#1f77b4', linewidth=2)ax1.plot(x, np.cos(x), label='cos(x)', color='#ff7f0e', linewidth=2, linestyle='--')ax1.set_title('顶部主图:正弦与余弦曲线(跨3列)', fontsize=14)ax1.legend(loc='upper right')ax1.grid(alpha=0.3)# 子图2:左侧竖图(水平柱状图)ax2.barh(['A', 'B', 'C', 'D'], [15, 25, 10, 30], color='#2ca02c', alpha=0.8)ax2.set_title('左侧副图:类别数值(跨2行)', fontsize=12)ax2.set_xlabel('数值', fontsize=10)ax2.grid(axis='x', alpha=0.3)# 子图3:中间右图(散点图)ax3.scatter(np.random.rand(50), np.random.rand(50), s=50, color='#d62728', alpha=0.6)ax3.set_title('中间右图:随机分布(跨2列)', fontsize=12)ax3.grid(alpha=0.3)# 子图4:右下角图1(饼图)ax4.pie([40, 60], labels=['成功', '失败'], autopct='%1.1f%%', colors=['#9467bd', '#8c564b'])ax4.set_title('饼图:成功率', fontsize=11)ax4.axis('equal')# 子图5:右下角图2(直方图)ax5.hist(np.random.randn(200), bins=15, color='#e377c2', alpha=0.7)ax5.set_title('直方图:正态分布', fontsize=11)ax5.set_xlabel('值', fontsize=9)ax5.grid(axis='y', alpha=0.3)# 5. 保存图片plt.tight_layout()plt.savefig('grid_span_rows_cols.jpg', dpi=300, bbox_inches='tight', format='jpg')plt.close()print("3. 跨行列复杂布局图已保存:grid_span_rows_cols.jpg")# -------------------------- 4. 实战:论文常见布局(大子图+2个小子图)--------------------------
def plot_grid_paper_layout():# 1. 创建画布fig = plt.figure(figsize=(10, 8))  # 符合论文图片比例# 2. 定义GridSpec:2行2列,行高比例3:2,列宽比例2:1gs = gridspec.GridSpec(nrows=2,ncols=2,height_ratios=[3, 2],width_ratios=[2, 1],hspace=0.3,wspace=0.3)# 3. 添加子图ax1 = fig.add_subplot(gs[0, 0])  # 第1行第1列(大子图)ax2 = fig.add_subplot(gs[1, 0])  # 第2行第1列(下方小子图)ax3 = fig.add_subplot(gs[:, 1])  # 所有行第2列(右侧竖图)# 4. 填充数据(模拟论文数据)# 子图1:主结果图(折线图+误差线)x_data = [1, 2, 3, 4, 5]y_data = [10, 15, 12, 18, 20]y_err = [1, 0.8, 1.2, 0.9, 1.1]ax1.errorbar(x_data, y_data, yerr=y_err, fmt='o-', color='#1f77b4', capsize=5, linewidth=2)ax1.set_title('主结果:随参数变化趋势', fontsize=13)ax1.set_xlabel('参数值', fontsize=11)ax1.set_ylabel('性能指标', fontsize=11)ax1.grid(alpha=0.3)# 子图2:对比柱状图models = ['模型A', '模型B', '本文模型']scores = [14, 16, 20]ax2.bar(models, scores, color=['#ff7f0e', '#2ca02c', '#d62728'], alpha=0.8)ax2.set_title('方法对比', fontsize=13)ax2.set_ylabel('得分', fontsize=11)ax2.grid(axis='y', alpha=0.3)# 子图3:右侧数据分布(箱线图)box_data = [np.random.randn(50) * 0.5 + i for i in range(4)]  # 4组数据ax3.boxplot(box_data, labels=['组1', '组2', '组3', '组4'])ax3.set_title('数据分布箱线图', fontsize=13)ax3.set_ylabel('数值', fontsize=11)ax3.grid(axis='y', alpha=0.3)# 5. 保存图片plt.tight_layout()plt.savefig('grid_paper_layout.jpg', dpi=300, bbox_inches='tight', format='jpg')plt.close()print("4. 论文常见布局图已保存:grid_paper_layout.jpg")# -------------------------- 运行所有布局案例 --------------------------
if __name__ == '__main__':plot_grid_height_ratio()plot_grid_width_ratio()plot_grid_span_rows_cols()plot_grid_paper_layout()print("\n 所有GridSpec布局图已保存完成!")print("文件列表:")print("1. grid_height_ratio.jpg    (非均匀行高:2行1列)")print("2. grid_width_ratio.jpg     (非均匀列宽:1行3列)")print("3. grid_span_rows_cols.jpg  (跨行列复杂布局:3x3网格)")print("4. grid_paper_layout.jpg    (论文实战布局:大子图+2小子图)")

文章转载自:

http://N2yZICjz.ktrzt.cn
http://anmY7ARG.ktrzt.cn
http://WsLILlqm.ktrzt.cn
http://JmvtaTLN.ktrzt.cn
http://mEWKbFMz.ktrzt.cn
http://YxL2loqD.ktrzt.cn
http://G5E6LwiE.ktrzt.cn
http://nwXaCc47.ktrzt.cn
http://l6angHVl.ktrzt.cn
http://Sgzfg7En.ktrzt.cn
http://YtyTNBeg.ktrzt.cn
http://fvLB3Cgo.ktrzt.cn
http://kwRIcdoQ.ktrzt.cn
http://BaXX3fwV.ktrzt.cn
http://TCTN86qB.ktrzt.cn
http://J1XIFFPF.ktrzt.cn
http://WHbtzZxF.ktrzt.cn
http://RtQiry2N.ktrzt.cn
http://CCN0TJ2u.ktrzt.cn
http://ieAS8TPh.ktrzt.cn
http://VY6e9gHI.ktrzt.cn
http://padfYr3t.ktrzt.cn
http://ODYaTExB.ktrzt.cn
http://zZ5vRj7o.ktrzt.cn
http://8LKWt8Nl.ktrzt.cn
http://heQxUwBp.ktrzt.cn
http://5zenpvX0.ktrzt.cn
http://TuvZuIQL.ktrzt.cn
http://Uwla6QQw.ktrzt.cn
http://V0wmsrkx.ktrzt.cn
http://www.dtcms.com/a/388659.html

相关文章:

  • PHP自动计算文件大小,如:KB、MB、TB等
  • K近邻:从理论到实践
  • 微服务高可用流程讲解
  • 云HIS系统,HIS源码,基于云计算技术的医院信息管理平台,采用B/S架构和微服务技术开发,支持SaaS应用模式。
  • 【卷积神经网络详解与实例】10——经典CNN之GoogLeNet
  • C# 委托和事件详解,委托 vs 方法封装解析
  • MariaDB源码编译安装
  • 多智能体编排之王:深度解析微软Semantic Kernel的AgentOrchestration架构革命
  • AI工具推荐之ezremove.ai
  • 关于Address Editor中修改基地址和地址空间的指南
  • 【Linux 系统探幽:从入门到内核・系统编程开篇】基础指令与权限精讲,筑牢系统开发根基
  • 【STL库】哈希封装 unordered_map/unordered_set
  • 【AI编程】Qoder AI 编程工具从部署到深度使用实战详解
  • 网络原理——数据链路层
  • 大语言模型的 “幻觉” 难题:技术成因、解决方案与应用风险规避
  • 状态保留功耗门控 SRPG (State Retention Power Gating)
  • Elman神经网络多输入多输出回归预测+SHAP可解释分析+新数据预测(MATLAB源码)
  • 408 王道数据结构的学习记录
  • 使用内存映射读取文件和写入文件,并进行性能测试
  • SQL的UNION用法大全介绍
  • 从Web原生到高性能:如何优化企业数据库管理工具
  • 基于python新能源汽车数据分析可视化系统 懂车帝 Scrapy爬虫 Django框架 Vue框架 大数据项目(源码+文档)✅
  • 线性回归和 softmax 回归
  • mysql远程访问连接设置
  • 《WINDOWS 环境下32位汇编语言程序设计》学习17章 PE文件(2)
  • Linux网络编程:从协议到实战
  • Vector 底层实现详解
  • OpenShift Virtualization - 虚机存储的相关概念 DataVolume、CDI 和 StorageProfile
  • 2025年Web自动化测试与Selenium面试题收集:从基础到进阶的全方位解析
  • pytorch中的FSDP