目录8
文章/Matplotlib/第 24 章
向量场
Matplotlib · 第 24 / 43 章
665 字约 2 分钟
quiver() —— 向量场箭头
quiver() 在每个取样点上画一个箭头,箭头方向 = (U, V) 的方向,长度 ∝ 向量模长。它回答的是「每一点往哪走、走多快」。缺点很明确:密度一高就糊,而且箭头长度受 scale 控制,跨图比较时必须统一。
Python20 行
Axes.quiver(
X, Y, U, V, # 位置 + 两个分量;也可以只给 (U, V)
C=None, # ★ 第 5 个位置参数:按这个值给箭头上色
units="width", # 'width' / 'xy' / 'inches' / 'dots'
angles="uv", # ★ 'uv'(按方向算角度)/ 'xy'(按数据坐标)
scale=None, # 缩放系数:值越大箭头越短
scale_units=None, # 与 scale 配套的单位
width=0.005, # 箭杆宽度(相对子图宽度)
headwidth=3, # 箭头宽 = width 的倍数
headlength=5, # 箭头长 = width 的倍数
headaxislength=4.5,# 箭头与箭杆的重叠长度
minshaft=1, # 最小箭杆长度(短路时不画箭头)
minlength=1, # 短于此长度的向量不画
pivot="tail", # ★ 箭头锚点:tail / mid / middle / tip
color=None,
alpha=None,
clim=None,
data=None,
**kwargs
)| 参数 | 一句话 | 默认值的影响 |
|---|---|---|
U / V |
两个分量 | 单位不必归一,长度会按模长体现 |
C |
上色依据 | 不给就单色;给了自动配 cmap |
scale |
长度缩放 | 和箭头长度成反比 |
angles |
角度算法 | 'uv'(视觉角度)/ 'xy'(真实斜率) |
pivot |
锚点 | 'tail':格点是箭尾 |
width / headwidth / headlength |
箭头形状 | 相对 width 的倍数 |
minlength |
最小可见长度 | 1,短向量直接丢掉 |
最小示例
Python12 行
import numpy as np
import matplotlib.pyplot as plt
xq = np.linspace(-2, 2, 11)
yq = np.linspace(-2, 2, 11)
Xq, Yq = np.meshgrid(xq, yq)
Uq = -Yq * 0.8 # 绕原点的旋转场
Vq = Xq * 0.8
fig, ax = plt.subplots()
ax.quiver(Xq, Yq, Uq, Vq, scale=30)
plt.show()
scale:和箭头长度成反比
Python2 行
ax.quiver(Xq, Yq, Uq, Vq, scale=20) # 箭头长(会冲出坐标框)
ax.quiver(Xq, Yq, Uq, Vq, scale=60) # 箭头短(留出大片空白)这条关系经常记反:scale 是除数。scale 越大 → 同样的模长画出越短的箭头。
units 决定“长度”以什么为参照:'width'(默认,子图宽度的倍数)、'xy'(数据坐标)、'inches'、'dots'。想画“物理上正确”的箭头(比如速度矢量在数据坐标里的真实长度)用 units="xy" + scale=1。
C:按模长或第三维上色
Python3 行
M = np.hypot(Uq, Vq)
q = ax.quiver(Xq, Yq, Uq, Vq, M, cmap="viridis", scale=25)
fig.colorbar(q, ax=ax)第 5 个位置参数就是 C。只能按标量上色——想按方向区分颜色得先算 arctan2(V, U) 再传进去。
pivot / angles:锚点和角度算法
Python2 行
ax.quiver(Xq, Yq, Uq, Vq, scale=25, pivot="mid")
ax.quiver(Xq, Yq, Uq, Vq, scale=25, angles="xy")pivot="tail"(默认)→ 格点是箭尾;"mid"→ 格点是箭头中点;"tip"→ 格点是箭尖。angles="uv"(默认)→ 箭头方向由(U, V)直接决定,和坐标轴比例无关;"xy"→ 按数据坐标算,坐标轴不等比例时箭头会歪。
画流场默认值通常就对;画“真实的力/位移”(比如地图上的风)时 angles="xy" + units="xy" 才是物理正确的组合。
width / headwidth / headlength:箭头形状
Python2 行
ax.quiver(Xq, Yq, Uq, Vq, scale=25,
width=0.006, headwidth=4, headlength=6, headaxislength=5)width 是箭杆宽度(相对子图宽度的比例,默认 0.005),后三个都是**width 的倍数**,不是绝对值。所以放大 width 会让整个箭头等比变粗。
箭头太密时先减 width(让它细),比减 scale(让它短)更能保持可读性。
返回对象
Python14 行
q = ax.quiver(Xq, Yq, Uq, Vq)
print(type(q).__name__)
# 输出: Quiver
print(q.U.shape, q.V.shape)
# 输出: (121,) (121,)
print(q.scale, q.pivot, q.angles)
# 输出: None tail uv ← scale=None 表示「自动算缩放」
q.set_UVC(Uq * 2, Vq * 2) # ★ 换数据:动画里比重新 quiver 快得多
q.set_array(np.hypot(Uq, Vq))
q.set_clim(0, 3)
plt.show()Quiver 是一个 Collection,q.U / q.V 存的是扁平化后的分量(11×11 = 121)。做动态场(风场动画、粒子流)时用 set_UVC() 更新,不要每帧重建。
注意事项
scale与箭头长度成反比,跨图比较必须固定scale和scale_units。- 默认
angles="uv"时箭头方向不受坐标轴比例影响;"xy"才会。 C只能接标量;按方向上色要先算arctan2。width及其倍数是相对量,改子图尺寸后视觉粗细会变。- 箭头相互覆盖严重时,用
streamplot替代——quiver不适合表达“连续流线”。 q.U是扁平数组,形状还原要用.reshape(X.shape)。
综合示例:旋转场 / 模长上色 / 稀疏箭头
Python37 行
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
xq = np.linspace(-2, 2, 15)
yq = np.linspace(-2, 2, 15)
Xq, Yq = np.meshgrid(xq, yq)
# 涡 + 发散:U、V 都是 (X, Y) 的函数
Uq = -Yq * 0.7 + Xq * 0.25
Vq = Xq * 0.7 + Yq * 0.25
M = np.hypot(Uq, Vq)
fig, axes = plt.subplots(1, 3, figsize=(15, 4.6))
# ---- (a) 单色 + 箭头从格点长出来 ----
axes[0].quiver(Xq, Yq, Uq, Vq, scale=28, width=0.005)
axes[0].set_title("(a) scale=28 + pivot='tail'")
# ---- (b) 按模长上色 ----
q = axes[1].quiver(Xq, Yq, Uq, Vq, M, cmap="plasma", scale=28, width=0.006)
fig.colorbar(q, ax=axes[1], label="|v|")
axes[1].set_title("(b) 第 5 参数 = 模长")
# ---- (c) 细箭头 + 锚点居中,密集场也不糊 ----
axes[2].quiver(Xq, Yq, Uq, Vq, scale=30, width=0.003, pivot="mid",
headwidth=3.5, headlength=5, minlength=0.5)
axes[2].set_title("(c) width=0.003 + pivot='mid'")
for ax in axes:
ax.set_aspect("equal")
ax.set_xlim(-2.2, 2.2)
ax.set_ylim(-2.2, 2.2)
plt.tight_layout()
plt.show()(a) 和 (c) 讲同一件事:同样的数据,width 从 0.005 降到 0.003、锚点改成 mid,密集场立刻清爽一大截。