HOWTO · Matplotlib
Matplotlib 中的叠加图
本文介绍如何在 Matplotlib 中叠加绘图,并提供实用示例和清晰的讲解。了解组合不同类型可视化图表(包括折线图和柱状图)的最佳方法,提升数据呈现的叙事效果。探索如何创建能够有效传达洞见和对比关系的分层图形。
本页内容
在 Matplotlib 中叠加绘图时,让每组数据都绘制在同一个 Axes 对象上。这样可以在同一坐标系中比较相关数值。如果数据需要不同的刻度,或分开显示更易阅读,请使用多个子图;每个子图都有自己的 Axes。
方法 1:叠加折线图
在同一个坐标轴上多次调用 plot()。下面的示例比较相同 x 位置上的正弦值和余弦值。每次调用都会添加一条线,传入的标签会成为同一个图例中的条目。示例中的图表标题、坐标轴标签和图例条目都保留为英文,例如 “Sine” 和 “Cosine”;它们不会显示为中文。
请在可显示 Matplotlib 图形的环境中运行此示例;它会打开图形,并将 line-overlay.png 保存到当前目录。在无头环境中,保存的 PNG 文件仍可查看结果。
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, ax = plt.subplots()
ax.plot(x, np.sin(x), label="Sine", color="blue")
ax.plot(x, np.cos(x), label="Cosine", color="red")
ax.set(title="Sine and cosine", xlabel="x", ylabel="Value")
ax.legend()
fig.savefig("line-overlay.png", dpi=150, bbox_inches="tight")
plt.show()
plt.close(fig)
两条线共用相同的 x 轴和 y 轴刻度,因此可以轻松比较每个 x 位置上的数值。如果数据系列的单位不同或取值范围相差很大,共用 y 轴可能会造成误导;此时可考虑使用多个子图,或使用标注清楚的次坐标轴。
方法 2:叠加柱状图和折线图
当柱状图和折线图表示相同类别,且数值具有可比性时,可以将它们绘制在同一个坐标轴上。使用数值型类别位置,让标记落在柱子中心。适当设置柱子的透明度,有助于让折线保持可见。
运行此示例;它会打开图形,并将 bar-line-overlay.png 保存到当前目录。
import matplotlib.pyplot as plt
categories = ["A", "B", "C", "D"]
positions = range(len(categories))
bar_values = [3, 7, 2, 5]
line_values = [4, 6, 3, 4]
fig, ax = plt.subplots()
ax.bar(positions, bar_values, width=0.65, alpha=0.55, label="Bar values")
ax.plot(positions, line_values, color="darkorange", marker="o", label="Line values")
ax.set_xticks(list(positions), categories)
ax.set(xlabel="Category", ylabel="Value", title="Bar and line overlay")
ax.legend()
fig.savefig("bar-line-overlay.png", dpi=150, bbox_inches="tight")
plt.show()
plt.close(fig)
此示例使用一个 y 轴,因为两个数据系列的数值范围具有可比性。如果某个系列表示不同的量或单位,请明确说明,并使用不同坐标轴或多个子图,避免让读者误以为两者的高度可以直接比较。
使用 zorder 控制绘图元素的前后层次
Matplotlib 会按照 zorder 的值绘制图形元素:值较大的元素显示在值较小的元素前面。如果希望折线保持在柱子上方,请明确设置该值。运行此示例;它会打开图形,并将 zorder-overlay.png 保存到当前目录。
import matplotlib.pyplot as plt
positions = [0, 1, 2]
fig, ax = plt.subplots()
ax.bar(positions, [3, 5, 4], alpha=0.6, zorder=1)
ax.plot(positions, [4, 3, 5], color="darkorange", marker="o", zorder=2)
fig.savefig("zorder-overlay.png", dpi=150, bbox_inches="tight")
plt.show()
plt.close(fig)
较高的 zorder 值控制绘制顺序,不会改变数值刻度或数据值。它有助于让标记或网格线清晰可见,但无法解决需要不同刻度的数据重叠问题。
方法 3:使用子图组织多个图表
plt.subplots() 会创建彼此独立的坐标轴。如下例所示,你可以在一个子图中叠加相关数据系列,并在另一个子图中绘制不同的数据系列。这样可以有条理地呈现不同的比较,而不会暗示所有数据都共用同一刻度。
运行此示例;它会打开图形,并将 subplot-overlay.png 保存到当前目录:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 100)
fig, axes = plt.subplots(2, 1, figsize=(8, 6))
axes[0].plot(x, np.sin(x), label="Sine")
axes[0].plot(x, np.cos(x), label="Cosine")
axes[0].set_ylabel("Value")
axes[0].legend()
tangent = np.tan(x)
tangent[np.abs(tangent) > 5] = np.nan
axes[1].plot(x, tangent, color="green", label="Tangent")
axes[1].set_ylim(-5, 5)
axes[1].set_xlabel("x")
axes[1].set_ylabel("Value")
axes[1].legend()
fig.tight_layout()
fig.savefig("subplot-overlay.png", dpi=150, bbox_inches="tight")
plt.show()
plt.close(fig)
第一个坐标轴包含两条叠加的折线;第二个坐标轴则显示位于图示 y 轴范围内的正切函数线段。绘图前会屏蔽绝对值大于 5 的数值,因此 Matplotlib 不会跨越正切函数的垂直渐近线绘制线段。tight_layout() 会调整间距,降低标签互相重叠的可能性。数据系列较多时,只在子图有助于区分比较内容的情况下才增加子图;与少量重点明确的图表相比,过于密集的叠加图可能更难理解。
总结
在 Matplotlib 中,调用同一个 Axes 上的绘图方法即可叠加图表。请使用图例、清晰的标签和相容的刻度;需要控制绘制前后顺序时,可设置 zorder。如果数据应保持区分,请使用多个子图,并控制叠加的数据系列数量,确保图表易于阅读。
常见问题
-
为什么要在 Matplotlib 中叠加绘图?
叠加图可以在同一视图中呈现相关数据集;当它们使用有意义且相容的刻度时,更容易比较趋势和数值。 -
可以组合不同类型的图表吗?
可以。例如,当类别和数值能够清楚地进行比较时,可以在同一个坐标轴上绘制柱状图和折线图。 -
如何自定义叠加图?
在绘图调用中设置颜色、标记、线型、透明度、标签和zorder。图例和坐标轴标签应明确对应各个数据系列。 -
可以叠加多少个图表?
没有固定上限,但线条或标记过多会让图表显得杂乱。如果标签或比较内容变得难以辨认,可将数据拆分到多个子图中。 -
如何将叠加图保存为图像?
在关闭图形前调用fig.savefig("overlay.png", dpi=150, bbox_inches="tight")。这会将当前图形保存为 PNG 文件;需要其他格式时,可改用相应的受支持文件扩展名。