📚 章节概述
数据可视化中,布局设计至关重要。本章深入讲解Matplotlib中的多种布局方案, 从基础的subplots到灵活的GridSpec,再到复杂的嵌套子图系统,帮助你创建专业级的复合图表。
3.1 图片对象规格
plt.rcParams - Matplotlib全局参数
plt.rcParams 是一个字典对象, 包含了Matplotlib所有可配置的参数。通过修改这些参数,可以定制图表的各个方面。
主要参数类别:
import matplotlib.pyplot as plt
import numpy as np
# 查看所有默认参数
plt.rcParams
# 常用参数修改示例
plt.rcParams['figure.figsize'] = (10, 6) # 图片大小
plt.rcParams['font.size'] = 12 # 字体大小
plt.rcParams['axes.grid'] = True # 显示网格
plt.rcParams['grid.alpha'] = 0.3 # 网格透明度💡 最佳实践:在大型项目中,建议创建统一的样式配置文件(.mplstyle),保持整个项目图表风格一致。
MATLAB Peaks 函数探索器
经典的三维测试函数,展示多峰地形
📐 函数定义
z = 3(1-x)² exp(-(x²)-(y+1)²) - 10(x/5-x³-y⁵) exp(-x²-y²) - (1/3) exp(-(x+1)²-y²)- • 三个高斯型峰的线性组合
- • 定义域:x, y ∈ [-3, 3]
- • 包含多个局部极值点
- • 经典的优化测试函数
- • 测试3D绘图能力
- • 演示曲面可视化
- • 优化算法验证
- • 多峰函数分析
3.2 混合二维、三维可视化方案
MATLAB Peaks函数可视化
Peaks函数是MATLAB中经典的测试函数,用于展示二元函数的可视化效果。 本节展示如何使用Python重现该函数,并进行多种形式的可视化。
from sympy import symbols, exp, lambdify
import numpy as np
x, y = symbols("x, y")
# 定义MATLAB二元函数 peaks()
f_xy = 3*(1-x)**2*exp(-(x**2) - (y+1)**2) \
- 10*(x/5 - x**3 - y**5)*exp(-x**2-y**2) \
- 1/3*exp(-(x+1)**2 - y**2)
# 转换为Python函数
f_xy_fcn = lambdify([x,y], f_xy)
# 创建网格
x_vals = np.linspace(-3, 3, 100)
y_vals = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x_vals, y_vals)
Z = f_xy_fcn(X, Y)- 等高线图(contour)
- 填充等高线(contourf)
- 热力图(imshow)
- 矢量场(quiver)
- 曲面图(plot_surface)
- 线框图(plot_wireframe)
- 三维等高线(contour3D)
- 投影等高线
3.3 使用subplots绘制规则网格布局
subplots - 快速创建规则网格
plt.subplots() 是创建多子图最简单的方法, 适用于规则的行列布局。
from scipy.stats import norm
import matplotlib.pyplot as plt
import numpy as np
# 创建5x5的子图网格
fig, axs = plt.subplots(nrows=5, ncols=5, figsize=(10, 10))
x_array = np.linspace(-5, 5, 200)
mu_array = [-2, -1, 0, 1, 2]
sigma_array = [0.5, 0.75, 1, 1.5, 2]
# 使用meshgrid生成参数组合
mu_array_, sigma_array_ = np.meshgrid(mu_array, sigma_array)
# 遍历每个子图
for mu_idx, sigma_idx, ax in zip(mu_array_.ravel(),
sigma_array_.ravel(),
axs.ravel()):
# 计算一元高斯分布PDF
pdf_vals = norm.pdf(x_array, loc=mu_idx, scale=sigma_idx)
# 绘制曲线
ax.plot(x_array, pdf_vals, 'b-', linewidth=1.5)
ax.fill_between(x_array, pdf_vals, alpha=0.2)
# 设置标题
ax.set_title(f'μ={mu_idx}, σ={sigma_idx}', fontsize=8)
ax.set_xlim(-5, 5)
ax.set_ylim(0, None)
plt.tight_layout()
plt.show()📊 一元高斯分布参数效果
一元高斯分布探索器
调节均值μ和标准差σ,观察分布形态变化
📊 参数效果说明
f(x) = (1 / (σ√(2π))) × exp(-(x-μ)² / (2σ²))Beta分布可视化
Beta分布是定义在[0,1]区间上的连续概率分布,由两个形状参数α和β控制。
from scipy.stats import beta
x_array = np.linspace(0, 1, 200)
alpha_array = [0.5, 1, 2, 4, 8]
beta_array = [0.5, 1, 2, 4, 8]
fig, axs = plt.subplots(nrows=5, ncols=5, figsize=(10, 10))
alpha_array_, beta_array_ = np.meshgrid(alpha_array, beta_array)
for alpha_idx, beta_idx, ax in zip(alpha_array_.ravel(),
beta_array_.ravel(),
axs.ravel()):
pdf_vals = beta.pdf(x_array, alpha_idx, beta_idx)
ax.plot(x_array, pdf_vals, 'r-', linewidth=1.5)
ax.fill_between(x_array, pdf_vals, alpha=0.2, color='red')
ax.set_title(f'α={alpha_idx}, β={beta_idx}', fontsize=8)
ax.set_xlim(0, 1)
plt.tight_layout()📊 Beta分布形状特点
- α < 1, β < 1:U形分布,两端概率密度大
- α = β = 1:均匀分布
- α > 1, β > 1:单峰分布,峰值位置取决于α和β的相对大小
- α = β:关于0.5对称
Beta分布探索器
调节形状参数α和β,观察分布形态变化
📊 参数效果说明
μ = α / (α + β) = 0.286mode = (α-1) / (α+β-2) = 0.200- • α增大:分布右移,更集中于大值
- • α < 1:左端趋近无穷
- • α = 1:左端有限值
- • α > 1:左端为零
- • β增大:分布左移,更集中于小值
- • β < 1:右端趋近无穷
- • β = 1:右端有限值
- • β > 1:右端为零
f(x; α, β) = [x^(α-1) × (1-x)^(β-1)] / B(α, β), x ∈ [0,1]3.4 使用GridSpec创建灵活布局
GridSpec - 自定义子图大小和位置
GridSpec提供了比subplots更灵活的布局控制,可以创建不同大小的子图, 实现主图与边缘分布图的组合布局。
import matplotlib.pyplot as plt
import numpy as np
# 生成二元高斯分布随机数
mean = [0, 0]
cov = [[1, 1], [1, 2]]
x, y = np.random.multivariate_normal(mean, cov, 1000).T
# 创建4x4的GridSpec
fig = plt.figure(figsize=(6, 6))
grid = plt.GridSpec(4, 4, hspace=0.3, wspace=0.3)
# 主图占据右上3x3区域
main_ax = fig.add_subplot(grid[:-1, 1:])
# x轴边缘直方图占据底部1x3区域
x_hist = fig.add_subplot(grid[-1, 1:], yticklabels=[])
# y轴边缘直方图占据左侧3x1区域
y_hist = fig.add_subplot(grid[:-1, 0], xticklabels=[])
# 绘制散点图
main_ax.plot(x, y, 'ob', markersize=3, alpha=0.2)
main_ax.set_xticks([])
main_ax.set_yticks([])
# 绘制x边缘直方图
x_hist.hist(x, 40, orientation='vertical', color='b',
edgecolor='white', linewidth=0.5)
x_hist.invert_yaxis() # 反转y轴,让直方图向下
x_hist.set_xticks([])
x_hist.set_yticks([])
# 绘制y边缘直方图
y_hist.hist(y, 40, orientation='horizontal', color='b',
edgecolor='white', linewidth=0.5)
y_hist.invert_xaxis() # 反转x轴,让直方图向左
y_hist.set_xticks([])
y_hist.set_yticks([])
plt.show()🎯 主图位于右上
grid[:-1, 1:]主图占据除最后一行和第一列外的区域
🎯 主图位于左下
grid[1:, :-1]主图占据除第一行和最后一列外的区域
💡 设计要点:边缘分布图展示了二维分布在各个维度上的投影,帮助理解数据的单变量特征。 这种布局在探索性数据分析中非常常用。
GridSpec 布局演示
灵活的子图网格系统,类似matplotlib的GridSpec
📐 当前布局特性
- • 主图区域 (2×2)
- • 侧边栏 (1×2)
- • 底部子图 (1×1 × 3)
- • 灵活的子图排列
- • 支持跨行跨列
- • 可以嵌套使用
- • 精确控制间距
- • 复杂的多子图布局
- • 仪表板设计
- • 数据报告可视化
- • 对比分析图表
本演示使用CSS Grid实现类似matplotlib GridSpec的功能:
- •
grid-cols-*- 定义列数 - •
grid-rows-*- 定义行数 - •
col-span-*- 跨列 - •
row-span-*- 跨行
3.5 Dirichlet分布与边缘Beta分布可视化
联合分布与边缘分布的GridSpec布局
Dirichlet分布是Beta分布在多维空间的推广。本节展示如何使用GridSpec 同时绘制Dirichlet联合分布的等高线和边缘Beta分布。
数学关系:
import scipy.stats as stats
import matplotlib.gridspec as gridspec
# Dirichlet参数
alpha_1, alpha_2, alpha_3 = 2, 2, 2
alpha_0 = alpha_1 + alpha_2 + alpha_3
# 创建网格
x1 = np.linspace(0, 1, 201)
x2 = np.linspace(0, 1, 201)
xx1, xx2 = np.meshgrid(x1, x2)
xx3 = 1.0 - xx1 - xx2
xx3 = np.where(xx3 > 0.0, xx3, np.nan)
# 计算Dirichlet PDF
alphas = np.array([alpha_1, alpha_2, alpha_3])
rv = stats.dirichlet(alphas)
PDF_ff = rv.pdf(np.array([xx1.ravel(), xx2.ravel(), xx3.ravel()]))
PDF_ff = np.reshape(PDF_ff, xx1.shape)
# 计算边缘Beta分布
beta_1 = alpha_0 - alpha_1
f_x1 = stats.beta.pdf(x1, alpha_1, beta_1)
beta_2 = alpha_0 - alpha_2
f_x2 = stats.beta.pdf(x2, alpha_2, beta_2)
# 创建2x2 GridSpec布局
fig = plt.figure(figsize=(6, 6))
gs = gridspec.GridSpec(2, 2,
width_ratios=[3, 1],
height_ratios=[3, 1])
# 左上:联合分布等高线
ax1 = plt.subplot(gs[0])
ax1.contour(xx1, xx2, PDF_ff, 20, cmap='RdYlBu_r')
ax1.set_title(f'Dirichlet({alpha_1}, {alpha_2}, {alpha_3})')
# 右上:x₂边缘分布
ax2 = plt.subplot(gs[1])
ax2.plot(f_x2, x2, color='#0070C0')
ax2.fill_between(f_x2, x2, alpha=0.2)
ax2.set_xlabel('PDF')
ax2.invert_xaxis()
# 左下:x₁边缘分布
ax3 = plt.subplot(gs[2])
ax3.plot(x1, f_x1, color='#0070C0')
ax3.fill_between(x1, f_x1, alpha=0.2)
ax3.set_ylabel('PDF')
# 右下:隐藏
ax4 = plt.subplot(gs[3])
ax4.set_visible(False)💡 布局特点:使用width_ratios和height_ratios参数, 可以精确控制主图与边缘图的尺寸比例,通常设为3:1或4:1效果最佳。
Dirichlet 分布探索器
多元概率分布的三元图可视化
参数设置
📊 分布参数信息
- • Beta分布的多元推广
- • 输出K个概率值,和为1
- • 用于表示概率分布的分布
- • α参数控制集中程度
- • 主题模型 (LDA)
- • 贝叶斯推断的先验
- • 多分类问题
- • 文档分类与聚类
• 三角形的每个顶点代表一个分量取值为1的情况
• 点在三角形内的位置表示三个分量的相对大小
• 点的颜色使用RGB映射,对应三个分量的值
• α值越大,样本越集中在对应顶点附近
3.6 使用subgridspec创建嵌套子图
多层次嵌套布局
subgridspec 允许在GridSpec的每个单元格内 再创建一个子GridSpec,实现复杂的多层次布局结构。
import matplotlib.pyplot as plt
import numpy as np
def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)):
"""生成参数化曲线"""
return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d)
fig = plt.figure(figsize=(8, 8), constrained_layout=False)
# 创建4x4的外层网格
outer_grid = fig.add_gridspec(4, 4, wspace=0, hspace=0)
# 在每个外层单元格中创建3x3的内层网格
for a in range(4):
for b in range(4):
# 嵌套GridSpec
inner_grid = outer_grid[a, b].subgridspec(3, 3,
wspace=0, hspace=0)
axs = inner_grid.subplots() # 创建内层所有子图
# 在每个内层子图中绘制参数曲线
for (c, d), ax in np.ndenumerate(axs):
ax.plot(*squiggle_xy(a + 1, b + 1, c + 1, d + 1))
ax.set(xticks=[], yticks=[])
# 只显示最外层边框
for ax in fig.get_axes():
ss = ax.get_subplotspec()
ax.spines.top.set_visible(ss.is_first_row())
ax.spines.bottom.set_visible(ss.is_last_row())
ax.spines.left.set_visible(ss.is_first_col())
ax.spines.right.set_visible(ss.is_last_col())
plt.show()📊 布局层次
- 外层:4×4 = 16个大格子
- 内层:每个大格子内3×3 = 9个小格子
- 总计:16×9 = 144个子图
🎨 应用场景
- 参数空间扫描
- 多层次数据对比
- 复杂模式展示
- 科学研究报告
⚠️ 注意事项:嵌套子图布局功能强大但也增加了复杂度。建议在确实需要展示多层次结构时使用, 并注意控制图片尺寸和分辨率,避免单个子图过小难以辨识。
📋 本章总结
核心知识点
- 1.plt.rcParams:全局参数配置,统一图表风格
- 2.plt.subplots:规则网格布局,快速创建多子图
- 3.GridSpec:灵活布局,自定义子图大小和位置
- 4.subgridspec:嵌套布局,实现多层次结构