HOWTO · Matplotlib
如何在 Matplotlib 中绘制水平线和垂直线
本教程介绍如何使用 axhline 和 axvline、hlines 和 vlines 以及 axhspan 和 axvspan 着色函数在 Matplotlib 中绘制水平线和垂直线。
本页内容
要在 Matplotlib 中绘制水平和垂直参考线,当线段应跨越坐标轴的一定比例时,选择 axhline 和 axvline;当线段的端点应固定为数据值时,选择 hlines 和 vlines。当目标是突出一整条区域而不是单个值时,axhspan 和 axvspan 会为两个位置之间的区域着色。每个示例都会将图形保存到临时 PNG 文件,并打印它所创建对象的坐标,因此你可以确切确认 Matplotlib 将线条或区域放置在哪里。
使用 axhline 和 axvline 在 Matplotlib 中绘制水平线和垂直线
使用 axhline 绘制水平线
axhline(y=...) 在数据坐标的 y 处放置一条水平线。它的 xmin 和 xmax 参数将左端和右端设置为坐标轴宽度的比例,通常从 0 到 1;它们不是 x 数据值。例如,xmin=0.1 和 xmax=0.9 会在两端各留出等于坐标轴宽度 10% 的边距。
import tempfile
from pathlib import Path
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
line = ax.axhline(y=2, xmin=0.1, xmax=0.9, color="tab:red")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
print("x extent (axes fraction):", line.get_xdata())
print("y position (data):", line.get_ydata())
with tempfile.TemporaryDirectory() as directory:
fig.savefig(Path(directory) / "plot.png")
plt.close(fig)
输出:
x extent (axes fraction): [0.1, 0.9]
y position (data): [2, 2]
打印的值证实了这种划分:位置是数据值 2,而范围则以坐标轴比例 0.1 和 0.9 存储。
线条保持在数据值 y=2 处。如果你更改 x 的范围,它的两端仍然跨越坐标轴宽度的 10% 到 90%,因此线段会随显示范围而调整。
使用 axvline 绘制垂直线
axvline(x=...) 在数据坐标的 x 处放置一条垂直线。它的 ymin 和 ymax 参数将底端和顶端设置为坐标轴高度的比例,通常从 0 到 1。例如,ymin=0.1 和 ymax=0.9 会在两端各留出等于坐标轴高度 10% 的边距。
import tempfile
from pathlib import Path
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
line = ax.axvline(x=2, ymin=0.1, ymax=0.9, color="tab:green")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
print("x position (data):", line.get_xdata())
print("y extent (axes fraction):", line.get_ydata())
with tempfile.TemporaryDirectory() as directory:
fig.savefig(Path(directory) / "plot.png")
plt.close(fig)
输出:
x position (data): [2, 2]
y extent (axes fraction): [0.1, 0.9]
这里存储的值正好相反:位置是数据值 2,范围是坐标轴比例对。
线条保持在数据值 x=2 处。如果你更改 y 的范围,它的两端仍然跨越坐标轴高度的 10% 到 90%。因此,每个 ax*line 函数都将数据坐标中的位置与按坐标轴比例测量的范围结合在一起。
使用 hlines 和 vlines 在 Matplotlib 中绘制水平线和垂直线
当线条的位置和两个端点都应使用数据坐标时,使用 hlines 和 vlines。对于 hlines,y 给出高度,xmin 和 xmax 给出端点的 x 值。对于 vlines,x 给出位置,ymin 和 ymax 给出端点的 y 值。更改绘图范围会改变哪些部分可见,而线条在数据坐标中的位置和端点保持不变。这两个函数都返回一个 LineCollection,并接受常用的样式参数,因此本示例还设置了虚线和点线样式,并通过 label 参数添加了图例。
import tempfile
from pathlib import Path
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
horizontal = ax.hlines(y=2, xmin=1, xmax=3, color="tab:red", linestyles="--",
linewidth=2, label="horizontal segment")
vertical = ax.vlines(x=2, ymin=1, ymax=3, color="tab:green", linestyles=":",
linewidth=2, label="vertical segment")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
ax.legend(loc="upper left")
print("horizontal segment endpoints:", horizontal.get_segments()[0].tolist())
print("vertical segment endpoints:", vertical.get_segments()[0].tolist())
with tempfile.TemporaryDirectory() as directory:
fig.savefig(Path(directory) / "plot.png")
plt.close(fig)
输出:
horizontal segment endpoints: [[1.0, 2.0], [3.0, 2.0]]
vertical segment endpoints: [[2.0, 1.0], [2.0, 3.0]]
打印的端点是纯粹的数据坐标:水平线段从 (1, 2) 到 (3, 2),垂直线段从 (2, 1) 到 (2, 3)。
由于所有四个端点都使用数据坐标,缩放或更改范围会改变每个线段的可见部分,而不是调整其端点以匹配坐标轴的比例。
使用 axhspan 和 axvspan 在 Matplotlib 中为区域着色
当单条线不够时,可以改为对两个值之间的区域着色。axhspan(ymin, ymax) 在坐标轴的整个宽度上填充两个 y 数据值之间的水平区域,axvspan(xmin, xmax) 在整个高度上填充两个 x 数据值之间的垂直区域。使用它们可以在数据背后标记可接受的范围、目标区域或关注的时间段。这两个函数都返回一个 Rectangle 补片。
import tempfile
from pathlib import Path
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
band_y = ax.axhspan(ymin=1.5, ymax=2.5, color="tab:orange", alpha=0.3,
label="y between 1.5 and 2.5")
band_x = ax.axvspan(xmin=1.5, xmax=2.5, color="tab:blue", alpha=0.15,
label="x between 1.5 and 2.5")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
ax.legend(loc="upper left")
print("horizontal band y range:", band_y.get_y(), "to", band_y.get_y() + band_y.get_height())
print("vertical band x range:", band_x.get_x(), "to", band_x.get_x() + band_x.get_width())
with tempfile.TemporaryDirectory() as directory:
fig.savefig(Path(directory) / "plot.png")
plt.close(fig)
输出:
horizontal band y range: 1.5 to 2.5
vertical band x range: 1.5 to 2.5
区域的边界始终使用数据坐标。与 axhline 一样,span 函数也接受横向方向的比例参数——axhspan 接受 xmin 和 xmax 作为坐标轴比例以限制区域的宽度,axvspan 接受 ymin 和 ymax——但以这种方式绘制的区域仍然以数据值开始和结束。
为什么 Matplotlib 中的水平线或垂直线可能不显示
两个检查就能解释几乎所有线条缺失的报告。第一个是类型错误:axhline 和 axvline 的比例参数必须是数字。将它们作为字符串传递——当值来自表单、CSV 文件或配置项时常见的失误——会在绘制任何内容之前引发 ValueError:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
ax.axhline(y=2, xmin="0.1", xmax="0.9", color="tab:red")
plt.close(fig)
输出:
ValueError: xmin must be a single scalar value, but got 0.1
先将值转换为数字,例如使用 float(...),相同的调用就会成功——本文的第一个示例正是使用数字比例的那个调用。
第二个检查是可见范围。即使线条的位置位于当前坐标轴范围之外,它也会以数据坐标创建,因此它存在于图形中,但被裁剪到视图之外:
import tempfile
from pathlib import Path
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot([0, 2, 4], [1, 3, 2], marker="o")
line = ax.axhline(y=20, color="tab:red")
ax.set(xlim=(0, 4), ylim=(0, 4), xlabel="x", ylabel="y")
ax.grid(True)
print("line y position:", line.get_ydata())
print("axes y limits:", tuple(float(v) for v in ax.get_ylim()))
with tempfile.TemporaryDirectory() as directory:
fig.savefig(Path(directory) / "plot.png")
plt.close(fig)
输出:
line y position: [20, 20]
axes y limits: (0.0, 4.0)
线条位于 y=20,而坐标轴止于 4.0。扩展范围以包含该位置——或者如果 20 是个错误则更正该值——线条就会出现。同样的检查适用于 hlines 和 vlines 的端点,以及落在范围之外的 span 边界。
在 Matplotlib 中绘制水平线和垂直线的结论
当位置是数据值但线条的范围应遵循坐标轴比例时,选择 axhline 或 axvline。当位置和两个端点都应保持为数据值时,选择 hlines 或 vlines;当需要突出两个值之间的整条区域而不是单条线时,使用 axhspan 或 axvspan。这种坐标选择决定了在更改绘图范围后线条的可见程度——而将存储的坐标与坐标轴范围进行比较,可以解释任何看似缺失的线条。