Thanks to visit codestin.com
Credit goes to github.com

Skip to content

BUG: numpy gradient yields incorrect results #28999

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
goznalo-git opened this issue May 18, 2025 · 7 comments
Closed

BUG: numpy gradient yields incorrect results #28999

goznalo-git opened this issue May 18, 2025 · 7 comments
Labels
00 - Bug 57 - Close? Issues which may be closable unless discussion continued

Comments

@goznalo-git
Copy link

Describe the issue:

I thought i was going mad about a 2D gradient calculation, so I made a simple check: a 2D gaussian should have all arrows pointing towards the peak. But that is not what I observe when plotting a quiver diagram, it looks more like the center being a hyperbolic point.

Reproduce the code example:

import numpy as np
import matplotlib.pyplot as plt

def gaussian_2d(x, y):
    return np.exp(-(x**2 + y**2) / 2)

x = np.linspace(-5, 5, 20)
y = np.linspace(-5, 5, 20)

X, Y = np.meshgrid(x, y)
Z = gaussian_2d(X, Y)

grad_x, grad_y = np.gradient(Z)

plt.figure(figsize=(8, 8))
plt.quiver(X, Y, grad_x, grad_y, color='b')
plt.xlabel('x')
plt.ylabel('y')
plt.show()

Error message:

Python and NumPy Versions:

Python 3.9.21
Numpy 2.0.2

Runtime Environment:

[{'numpy_version': '2.0.2',
'python': '3.9.21 (main, Feb 10 2025, 00:00:00) \n'
'[GCC 11.5.0 20240719 (Red Hat 11.5.0-5)]',
'uname': uname_result(system='Linux', node='XXX', release='5.14.0-578.el9.x86_64', version='#1 SMP PREEMPT_DYNAMIC Mon Apr 7 19:22:46 UTC 2025', machine='x86_64')},
{'simd_extensions': {'baseline': ['SSE', 'SSE2', 'SSE3'],
'found': ['SSSE3',
'SSE41',
'POPCNT',
'SSE42',
'AVX',
'F16C',
'FMA3',
'AVX2',
'AVX512F',
'AVX512CD',
'AVX512_SKX',
'AVX512_CLX'],
'not_found': ['AVX512_KNL',
'AVX512_KNM',
'AVX512_CNL',
'AVX512_ICL']}},
{'architecture': 'SkylakeX',
'filepath': '/home/XXX/myenv/lib/python3.9/site-packages/numpy.libs/libscipy_openblas64_-99b71e71.so',
'internal_api': 'openblas',
'num_threads': 64,
'prefix': 'libscipy_openblas',
'threading_layer': 'pthreads',
'user_api': 'blas',
'version': '0.3.27'},
{'architecture': 'SkylakeX',
'filepath': '/home/XXX/myenv/lib/python3.9/site-packages/scipy.libs/libopenblasp-r0-01191904.3.27.so',
'internal_api': 'openblas',
'num_threads': 64,
'prefix': 'libopenblas',
'threading_layer': 'pthreads',
'user_api': 'blas',
'version': '0.3.27'}]

Context for the issue:

If this turns out to be a bug (and given how simple the reference code is i doubt I made a mistake) this is quite important, since gradients are all over the place.

@BryteLite

This comment has been minimized.

@BryteLite

This comment has been minimized.

@jorenham
Copy link
Member

Could you try again with the latest numpy==2.2.6 release on Python>=3.11?

@goznalo-git
Copy link
Author

Could you try again with the latest numpy==2.2.6 release on Python>=3.11?

I just did, same result

@ngoldbaum
Copy link
Member

ngoldbaum commented May 18, 2025

I think this is a misunderstanding of how np.gradient works. Its docstring says:

For two dimensional arrays, the return will be two arrays ordered by axis. In this example the first array stands for the gradient in rows and the second one in columns direction

The "gradient in rows" is the y gradient and the "gradient in columns" is the x gradient in the way you've plotted things. If you make the following modification:

grad_y, grad_x = np.gradient(Z)

Then you'll get a plot that looks like what you expect.

@ngoldbaum ngoldbaum added the 57 - Close? Issues which may be closable unless discussion continued label May 18, 2025
@goznalo-git
Copy link
Author

I think this is a misunderstanding of how np.gradient works. Its docstring says:

For two dimensional arrays, the return will be two arrays ordered by axis. In this example the first array stands for the gradient in rows and the second one in columns direction

The "gradient in rows" is the y gradient and the "gradient in columns" is the x gradient in the way you've plotted things. If you make the following modification:

grad_y, grad_x = np.gradient(Z)

Then you'll get a plot that looks like what you expect.

Okay, that is rather confusing, but yes, it indeed solves it. Thanks

@ngoldbaum
Copy link
Member

The row major/column major thing isn't really something we can do a whole lot about. It's a pretty fundamental part of how NumPy stores data, in C order. You can tell NumPy to store the data in Fortran order by specifying order="F", and then it'll also work how you would intuitively expect.

This is one way in which Matlab and Fortran are less confusing than Python and C. A lot of people also like 1-indexing too!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
00 - Bug 57 - Close? Issues which may be closable unless discussion continued
Projects
None yet
Development

No branches or pull requests

4 participants