pythonnumpygradient

Why my np.gradient calculation in R^2 doesn't fit with the analytical gradient calculation?


I'm trying to compute a gradient on a map using np.gradient, but I'm encountering issues. To simplify my problem I am trying on an analytical function

z = f(x,y) = -(x - 2)**2 - (y - 2)**2

np.gradient is not providing the expected results; the vectors should point towards the center. What am I doing wrong?

Here is the code that I am running:

import numpy as np
import matplotlib.pyplot as plt

# Define the grids for x and y
x = np.linspace(0, 4, 100)  # 100 points between 0 and 4
y = np.linspace(0, 4, 100)  # 100 points between 0 and 4
X, Y = np.meshgrid(x, y)  # Create a 2D grid

# Define the function f(x, y)
Z = -(X - 2)**2 - (Y - 2)**2

# Compute gradients numerically
dz_dx, dz_dy = np.gradient(Z, x, y)


# Downsampling to reduce the density of arrows
step = 10

plt.figure(figsize=(10, 8))
contour = plt.contourf(X, Y, Z, cmap='viridis', levels=50, alpha=0.8)
plt.colorbar(contour, label='f(x, y)')
plt.quiver(X[::step, ::step], Y[::step, ::step], dz_dx[::step, ::step], dz_dy[::step, ::step], 
           color='r', headlength=3, headwidth=4)
plt.title('Function $f(x, y) = -(x - 2)^2 - (y - 2)^2$ and its gradients (numerical)')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)

plt.show()

Solution

  • the problem is not in the gradient function, it is in the different indexing order of np.meshgrid and np.gradient.

    by default np.gradient assumes the indexing is the same order as the arguments, ie:

    Z[x,y] -> np.gradient(Z, x, y)
    

    whereas np.meshgrid default indexing results in the opposite indexing,

    Z[y,x] -> np.meshgrid(x,y)  # default indexing = 'xy'
    

    you didn't notice this bug because both X and Y are identical, if you made X and Y have different number of points you would get an error.

    I like to use Z[y,x], so just swap the order of arguments and return of np.gradient and you will get the correct result.

    dz_dy, dz_dx = np.gradient(Z, y, x)  # Z[y,x]