Matplotlib 不同变量范围下Quiver梯度向量不垂直等高线的正确绘制方法
问题本质
梯度在数学定义上始终是所在位置等高线的法向量,出现视觉上不垂直的偏差并非梯度计算错误,核心原因是matplotlib默认会自动适配画布宽高,使x、y轴上单个数据单位对应的屏幕物理长度不相等。
当x、y取值范围不同时,比如x范围[0,5]、y范围[0,10],在常规画布上x方向每单位对应的物理长度仅为y方向的一半。此时直接按数学分量绘制矢量,矢量的视觉斜率会与等高线的视觉切线斜率无法匹配,最终看起来失去垂直关系。
正确实现流程
不需要手动修正矢量分量的比例,仅需两步核心设置即可适配任意x、y取值范围:
- 第一步:强制坐标轴物理等比例
调用ax.set_aspect('equal', adjustable='box'),强制x轴和y轴上,1个数据单位对应的画布物理长度完全相等,从根源上消除比例拉伸带来的视觉偏差。之前尝试仅用
set_xlim、set_ylim调整范围但没有设置aspect,画布自动拉伸的状态下比例依然是错的,自然无法达到垂直效果。 - 第二步:指定quiver的角度计算逻辑
调用quiver时显式传入angles='xy'参数,告知绘图工具矢量方向完全按照数据坐标系计算,而非按屏幕坐标系的比例渲染。默认的quiver角度计算会受画布拉伸影响产生变形。
常见误区
- 手动缩放矢量分量的方案(如给dfdy乘固定scale值)不具备通用性:这种方法只是手动凑当前画布下的比例,一旦后续调整画布尺寸、坐标轴边距,固定的scale值就会再次引入偏差。
- 单独设置
units='xy'无法解决问题:该参数仅控制矢量长度的计量基准,不修正坐标轴本身的物理比例偏差。
可直接复用的完整代码
import numpy as np import matplotlib.pyplot as plt def f(x, y): return x + 0.1 * x * y def grad_f(x, y, norm=True): dfdx = 1 + 0.1 * y dfdy = 0.1 * x if norm: norm = np.linalg.norm((dfdx, dfdy), axis=0) dfdx /= norm dfdy /= norm return dfdx, dfdy # 不等范围的x、y采样 x = np.linspace(0, 5, 10) y = np.linspace(0, 10, 10) X, Y = np.meshgrid(x, y) Z = f(X, Y) dfdx, dfdy = grad_f(X, Y) fig, ax = plt.subplots(figsize=(8, 8)) ax.set_aspect('equal', adjustable='box') ax.contour(X, Y, Z, levels=np.arange(1, 20, 2)) ax.quiver(X, Y, dfdx, dfdy, Z, angles='xy') plt.show()
内容的提问来源于stack exchange,提问作者Haris M
相关产品推荐
相关产品推荐

