6

I'm not sure how to specify non-uniform spacing when using numpy.gradient.

Here's some example code for y = x**2.

import numpy as np
import matplotlib.pyplot as plt

x = [0.0, 2.0, 4.0, 8.0, 16.0]
y = [0.0, 4.0, 16.0, 64.0, 256.0]
dydx = [0.0, 4.0, 8.0, 16.0, 32.0] # analytical solution

spacing = [0.0, 2.0, 2.0, 4.0, 8.0] #added a zero at the start to get length matching up with y

m = np.gradient(y, spacing)

plt.plot(x, y, 'bo',
         x, dydx, 'r-', #analytical solution
         x, m, 'ro')    #calculated solution
plt.show()

The length of the spacing array will always be one less than the array I want to calculated the gradient of. Adding in a zero to get the lengths matching up (like in the example code above) gives incorrect answers, with an infinite gradient for one point.

I can't understand / follow the numpy.gradient documentation for non-uniform spacing (https://docs.scipy.org/doc/numpy/reference/generated/numpy.gradient.html)

How should I specify the spacing between points? Is there an alternative way of doing this?

Numpy version 1.9.2

Aaron
  • 85
  • 2
  • 7

1 Answers1

6

The API of the function is quite confusing. For non-uniformly spaced sample points, the gradient function takes the coordinates of the point rather than the spacings:

varargs : list of scalar or array, optional

Spacing between f values. Default unitary spacing for all dimensions. Spacing can be specified using:

  1. single scalar to specify a sample distance for all dimensions.
  2. N scalars to specify a constant sample distance for each dimension. i.e. dx, dy, dz, …
  3. N arrays to specify the coordinates of the values along each dimension of F. The length of the array must match the size of the corresponding dimension
  4. Any combination of N scalars/arrays with the meaning of 2. and 3.

I slightly modified your example:

import numpy as np
import matplotlib.pyplot as plt

x = np.random.rand(10)
x.sort()
y = x**2
dydx = 2*x

dydx_grad = np.gradient(y, x)

plt.plot(x, dydx, 'k-', label='analytical solution')
plt.plot(x, dydx_grad, 'ro', label='calculated solution')
plt.legend(); plt.xlabel('x'); plt.ylabel('dy / dx'); plt.show(); 
xdze2
  • 3,986
  • 2
  • 12
  • 29
  • This is still giving me incorrect gradients, even when I increase the number of points. I'm wondering if this is a problem on my end. I can't get the same answers as the numpy.gradient documentation, following their examples. Instead of their non-uniform spacing answer of [ 1. , 3. , 3.5, 6.7, 6.9, 2.5]) I get [ inf, 1.5, 1.67, 1., 1.125, 0.83] when I put the same f and x values in. I'll keep playing around with this and see if I can't get it working. Thanks. – Aaron Aug 11 '18 at 02:05
  • 1
    My version of numpy was out of date. Others have had similar issues (https://stackoverflow.com/questions/45776214/python-differentiation-using-numpy-not-producing-expected-output). I updated it and it now works as it should. On windows, this was pip install --upgrade numpy – Aaron Aug 11 '18 at 03:08