多图排版与高质量输出

在复杂的安全工程分析中,单一的物理量往往无法说明问题。灾变过程(如煤与瓦斯突出、岩爆)通常是多场耦合的结果。因此,在撰写学术论文或技术报告时,我们经常需要将两个或多个相关变量(例如:温度与压力、工作面进风量与瓦斯浓度、应力与应变)并排或上下对齐展示,以便直观地比对它们在同一时间或空间维度上的因果关系。

本节我们将探索面向对象绘图(OOP)最强大的优势之一:多子图矩阵式排版,并打通将这些图表导出为“出版级”高清文件的最后一步。

划分布局:创建多子图矩阵#

在第二节中,我们使用了 fig, ax = plt.subplots() 来创建单张图纸。其实,这个函数真正的威力在于它的 nrows(行数)和 ncols(列数)参数。

如果你想在一张画板上,上下叠放两张图纸,可以这样写:

# 创建 2 行 1 列的布局,共 2 张子图
fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(8, 8))

关键计算思维解析: 在这里,我们利用了 Python 的“解包(Unpacking)”特性。因为指定了 2 行 1 列,plt.subplots() 会生产出 2 个坐标系对象。我们将它们分别命名为 ax1(代表上半张图纸)和 ax2(代表下半张图纸)。接下来,你只需要像指挥两名独立的工人一样,分别对 ax1ax2 下达绘图指令,它们之间互不干扰。这就彻底避免了传统 plt.plot() 状态机模式下经常发生的“图表错乱”惨剧。

避免拥挤的神器:tight_layout()#

当你在一张画板上放置多张图纸时,经常会遇到一个非常丑陋的现象:上一张子图的 X 轴标签,和下一张子图的标题重叠在了一起。

不要试图去手动计算坐标来微调距离!在你的绘图代码末尾(通常在 plt.show() 或保存文件之前),只需要无脑加上这一行指令:

fig.tight_layout()

Matplotlib 的底层排版引擎会自动计算所有文本、标签和图例的边界,动态缩放坐标系的大小,确保所有元素完美错开,互不遮挡。这几乎是多图排版中必不可少的“黄金法则”。

输出学术成果:savefig()#

终端屏幕上显示出来的图表只是中间过程,我们的最终目的是将其插入到 Word 文档或 LaTeX 论文中。这需要使用图形对象的方法:fig.savefig()

为了满足核心期刊和工程报告的严苛要求,在保存文件时必须注意两个核心参数:

  • dpi (每英寸像素数):控制位图(如 PNG、JPG)的清晰度。学术出版一般要求至少为 300,推荐设置为 600
  • bbox_inches="tight":在导出时自动裁掉图表周围多余的白色边缘,这在排版论文时极其重要,可以避免图表周围出现大块无意义的留白。

此外,强烈建议使用矢量图格式。只要把文件名后缀写为 .pdf.svg,Matplotlib 就会自动导出矢量图。矢量图无论放大多少倍,线条和文字都不会出现马赛克模糊,这是学术论文的标准配置。

综合实战:通风异常与瓦斯积聚因果对析图#

现在,我们将本章学过的所有知识(跨平台中文字体、LaTeX 物理符号、样式定制、多图排版、高清导出)融会贯通,来处理一个经典的矿井灾害分析场景:展示“局部通风机故障导致风量下降”与“工作面瓦斯浓度飙升”之间的迟滞对应关系。

请运行以下代码,它将生成一张可以直接用来评定高级职称或发表 SCI 论文的绝美图表:

import matplotlib.pyplot as plt

# --- 1. 学术与工程环境终极标准配置 ---
plt.rcParams["font.family"] = "serif"
plt.rcParams["font.serif"] = ["SimSun", "Songti SC", "Noto Serif SC"]
plt.rcParams["axes.unicode_minus"] = False
plt.rcParams["mathtext.fontset"] = "stix"

# --- 2. 准备实验/监测数据 ---
time = [0, 5, 10, 15, 20, 25, 30, 35, 40] # 时间 t (min)
ventilation = [350, 345, 348, 120, 115, 110, 115, 120, 118] # 进风量 Q (m^3/min)
gas = [0.4, 0.42, 0.41, 0.45, 1.3, 1.8, 1.9, 1.85, 1.8]     # 瓦斯浓度 C (%)

# --- 3. 布局划分:2行1列 ---
# 开启 sharex=True,让上下两张图共享 X 轴(时间轴),非常利于垂直比对因果关系
fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1, figsize=(8, 7), sharex=True)

# --- 4. 操作 ax1:绘制进风量突变图(上半区) ---
ax1.plot(time, ventilation, color='seagreen', marker='s', linewidth=2, label="工作面进风量")
ax1.axvline(x=12, color='gray', linestyle='--', label="风机发生故障") # 添加垂直参考线指出故障时间
ax1.set_title(r"局部通风机故障对瓦斯涌出的影响对析", fontsize=14, pad=10)
ax1.set_ylabel(r"进风量 $Q$ ($\mathrm{m^3/min}$)")
ax1.grid(True, linestyle=':', alpha=0.6)
ax1.legend(loc='lower left')

# --- 5. 操作 ax2:绘制瓦斯浓度飙升图(下半区) ---
ax2.plot(time, gas, color='darkred', marker='o', linewidth=2, label="瓦斯绝对浓度")
ax2.axhline(y=1.0, color='red', linestyle='-.', label="报警阈值 (1.0%)") # 水平报警线
ax2.axvspan(15, 40, color='red', alpha=0.1) # 危险区域高亮

ax2.set_xlabel(r"监测时间 $t$ ($\mathrm{min}$)")
ax2.set_ylabel(r"瓦斯浓度 $C$ ($\%$)")
ax2.grid(True, linestyle=':', alpha=0.6)
ax2.legend(loc='upper left')

# --- 6. 防治标签重叠:自动紧凑排版 ---
fig.tight_layout()

# --- 7. 高质量输出(保存为文件) ---
# 导出为 600 DPI 的高清 PNG 和无损 PDF 矢量图,紧凑裁剪掉白边
# 注意:savefig 必须写在 plt.show() 之前!否则保存出来的将是一张白纸!
fig.savefig("ventilation_gas_analysis.png", dpi=600, bbox_inches="tight")
fig.savefig("ventilation_gas_analysis.pdf", bbox_inches="tight")

# 8. 在屏幕上展示
plt.show()

小结#

到这里,你已经掌握了利用 Python 和 Matplotlib 将枯燥的工程数据转化为专业出版级可视化图形的完整工作流。从配置字体环境、实例画布与坐标系,到定制样式、多图排版,最后完美导出——这一套基于“面向对象”的连招,就是你们未来撰写毕业论文、处理安全工程实测数据的终极武器。

熟练掌握它们,你的计算思维将不再仅仅停留在代码和控制台,而是真正拥有了向物理世界和工程同行生动表达的能力。

图表元素与样式定制课后作业