HOWTO · Matplotlib
如何在 Matplotlib 中绘制任意线段
使用 plot()、hlines()、vlines() 和 LineCollection 在 Matplotlib 中绘制有限线段。
本页内容
要在 Matplotlib 中绘制一条有限线段,请将两个端点的坐标传给 Axes.plot()。线段水平或垂直时使用 hlines() 或 vlines(),需要绘制许多相互独立的线段时使用 LineCollection。这些 API 使用数据坐标;axhline()、axvline() 和 axline() 解决的是另一类问题,即跨越坐标轴的线或无限直线。
示例使用 Python 和 Matplotlib。如果尚未安装 Matplotlib,请运行 python -m pip install matplotlib。每个可运行示例都会保存一个 PNG,因此可以在非交互环境中检查结果;想要使用交互式窗口时,可将 savefig() 替换为 plt.show()。
使用 plot() 绘制有限线段
对于从 (x1, y1) 到 (x2, y2) 的线段,向 plot() 传入一个包含两个 x 值的序列和一个包含两个 y 值的序列。Matplotlib 会连接处于相同位置的值,因此第一个 x/y 对是一个端点,第二个 x/y 对是另一个端点。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([3, 5], [1, 6], color="tab:green", marker="o")
ax.set(xlabel="x", ylabel="y", title="Finite segment with plot()")
fig.savefig("plot-segment.png", dpi=120)
print("saved: plot-segment.png")
saved: plot-segment.png
标记会使两个端点清晰可见。只有在确实要绘制折线时才添加更多成对的值:plot() 会连接连续的点,而不是创建互不相关的线段。
绘制有限水平或垂直线段
使用 hlines(y, xmin, xmax) 绘制水平线段,使用 vlines(x, ymin, ymax) 绘制垂直线段。保持不变的坐标是第一个参数,另外两个参数是在数据坐标中的有限端点。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.hlines(3, 2, 5, color="tab:red")
ax.vlines(6, 1, 5, color="tab:green")
ax.set(xlim=(0, 7), ylim=(0, 6), xlabel="x", ylabel="y")
fig.savefig("horizontal-vertical-segments.png", dpi=120)
print("saved: horizontal-vertical-segments.png")
saved: horizontal-vertical-segments.png
这里红色线段从 (2, 3) 延伸到 (5, 3),绿色线段从 (6, 1) 延伸到 (6, 5)。明确设置坐标范围可以清楚表达预期的数据范围,避免把被裁剪的线误认为更短的线段。
不要用跨越坐标轴的参考线替代
axhline() 和 axvline() 是有用的参考线,但它们会沿一个方向跨越坐标轴,而不是使用两个数据坐标端点。同样,axline() 表示一条经过指定点或具有指定斜率的无限直线。只有在图表确实需要这种行为时,才使用这些 API。
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
segment = ax.hlines(3, 2, 5, color="tab:red")
reference = ax.axhline(3, color="0.35", linestyle="--")
assert segment.get_segments()[0].tolist() == [[2.0, 3.0], [5.0, 3.0]]
assert reference.get_transform() is ax.get_yaxis_transform()
print("hlines endpoints: [2.0, 3.0] to [5.0, 3.0]")
print("axhline uses axes-relative x coordinates")
hlines endpoints: [2.0, 3.0] to [5.0, 3.0]
axhline uses axes-relative x coordinates
这个断言展示了两者的区别:hlines() 保留有限的数据端点,而 axhline() 使用相对于坐标轴的坐标来确定水平范围。在缩放、修改坐标范围或导出图表时,这一区别很重要。
使用 LineCollection 绘制许多独立线段
需要绘制许多不相连的线段时,可以从一系列由两个点组成的线段创建 LineCollection,再将其添加到坐标轴。调用 add_collection() 后再调用 autoscale(),可以让坐标轴将该集合纳入范围计算;如果图表需要固定的显示范围,则改为设置明确的坐标范围。
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
segments = [[(1, 10), (6, 9)], [(1, 7), (3, 6)]]
collection = LineCollection(segments, colors=["tab:red", "tab:green"])
fig, ax = plt.subplots()
ax.add_collection(collection)
ax.autoscale()
ax.set(xlabel="x", ylabel="y", title="Two independent segments")
fig.savefig("line-collection.png", dpi=120)
print("segments: 2")
print("saved: line-collection.png")
segments: 2
saved: line-collection.png
LineCollection 适合处理许多线段,因为它会将它们归入一个集合。它不会把一个线段的末端连接到下一个线段的起点,这正是它与向 plot() 传入更长点序列时的关键区别。
选择与几何形状匹配的 API
单条线段或连接路径使用 plot(),有限的轴向线段使用 hlines() 和 vlines(),一批互不相连的线段使用 LineCollection。只有在需要跨越坐标轴的引导线时才使用 axhline() 或 axvline(),并记住 axline() 表示无限直线。
有关参数详情和样式选项,请参阅官方的 plot() 文档、hlines() 文档、vlines() 文档 和 LineCollection 文档。以上示例是在记录的本地 Polyglot 容器中使用 Matplotlib 3.11.2 执行的。