
本文介绍如何利用 matplotlib 的 plt.subplot() 动态生成多子图,将字典中每个键值对对应的数据绘制成独立子图,并统一排布为每行4列的网格布局,避免逐个弹窗显示。
本文介绍如何利用 matplotlib 的 `plt.subplot()` 动态生成多子图,将字典中每个键值对对应的数据绘制成独立子图,并统一排布为每行4列的网格布局,避免逐个弹窗显示。
在使用 matplotlib 绘制多个相关序列图时,若直接用循环调用 plt.plot() + plt.show(),会导致每个图像单独弹出窗口,既不便于对比,也不符合出版或报告所需的紧凑排版要求。理想方案是将所有图表整合进一个 Figure 中,以子图(subplots)形式统一展示。
关键在于:动态计算所需行数、正确索引子图位置、复用 Axes 接口设置属性,并延迟统一渲染。由于目标是每行固定 4 列,行数应为 ⌈n/4⌉(向上取整),可借助 math.ceil(len(sequences) / 4) 计算;而 plt.subplot(rows, cols, index) 的 index 从 1 开始递增,需在循环中手动维护。
以下是完整、健壮的实现代码:
import matplotlib.pyplot as plt
import math
# 假设 sequences 是形如 {'seq1': 'acgt...', 'seq2': 'tgca...', ...} 的字典
# win_size() 和 get_windows() 已正确定义
n_plots = len(sequences)
n_cols = 4
n_rows = math.ceil(n_plots / n_cols)
for idx, (k, v) in enumerate(sequences.items(), start=1):
# 构造 x 轴:滑动窗口起始位置索引
x = range(len(v) - win_size() + 1)
# 计算每个窗口的 GC 比例
y = []
for window in get_windows(v):
gc_count = window.count("g") + window.count("c")
y.append(gc_count / len(window))
# 创建并配置当前子图
ax = plt.subplot(n_rows, n_cols, idx)
ax.plot(x, y, linewidth=1.2)
ax.set_title(k, fontsize=10, pad=6)
ax.set_xlabel("nucleotide position", fontsize=9)
ax.set_ylabel("GC proportion", fontsize=9)
ax.grid(True, alpha=0.3)
# 自动调整子图间距,防止标题/标签重叠
plt.tight_layout()
# 仅在循环结束后调用一次 show()
plt.show()
✅ 注意事项与优化建议:
- 使用 enumerate(..., start=1) 替代手动 id 计数,更 Pythonic 且不易出错;
- plt.tight_layout() 应置于循环外,否则会反复触发布局重算,影响性能甚至报错;
- 若字典项数不足 4 的倍数(如 7 项),末尾空白子图会自动留空,不影响显示;如需隐藏空白区域,可改用 plt.subplots() 配合 flatten() + 条件绘图(进阶用法);
- 对于大数据量序列,建议启用 plt.rcParams['agg.path.chunksize'] = 10000 防止绘制卡顿;
- 标题和坐标轴标签字体大小已微调,确保小尺寸子图中文字清晰可读。
该方法灵活适配任意长度字典,结构清晰、易于维护,是生物信息学中批量可视化基因序列 GC 含量等场景的标准实践。











