I want to create a contour plot of the function f(x, y) = x + 0.1xy and plot its gradient field on top. The problem: when variables of the function have different ranges, the gradient vectors are not perpendicular to the contours.
The function:
def f(x, y):
return x + 0.1 * x * y
Gradients:
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
All works well here:
x = np.linspace(0, 10, 10)
y = np.linspace(0, 10, 10)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
dfdx, dfdy = grad_f(X, Y)
ax.contour(X, Y, Z, levels=np.arange(1, 20, 2))
ax.quiver(X, Y, dfdx, dfdy, Z)
But suppose I want to plot variables with different ranges. Then gradient vectors no longer appear perpendicular to the contours.
x = np.linspace(0, 5, 10) # Range of x is [0, 5]
y = np.linspace(0, 10, 10)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)
dfdx, dfdy = grad_f(X, Y)
ax.contour(X, Y, Z, levels=np.arange(1, 20, 2))
ax.quiver(X, Y, dfdx, dfdy, Z)
I've tried:
- Using
set_xlimandset_ylimto restrict the plotting area (instead of having different ranges in the call tonp.linspace) - Setting
angles="xy"andunits="xy"in the call toquiver, per this - Experimenting with other parameters, such as
scale_units
Neither of these options solved the problem. What seems to have helped is this:
scale = max(y) / max(x)
ax.quiver(X, Y, dfdx, dfdy*scale, Z)
However, I'm not sure if this is indeed the right solution. What is the correct way to plot a quiver plot when the variables have different ranges?