14

I wrote the following code to perform a spline interpolation:

import numpy as np
import scipy as sp

x1 = [1., 0.88,  0.67,  0.50,  0.35,  0.27, 0.18,  0.11,  0.08,  0.04,  0.04,  0.02]
y1 = [0., 13.99, 27.99, 41.98, 55.98, 69.97, 83.97, 97.97, 111.96, 125.96, 139.95, 153.95]

x = np.array(x1)
y = np.array(y1)

new_length = 25
new_x = np.linspace(x.min(), x.max(), new_length)
new_y = sp.interpolate.interp1d(x, y, kind='cubic')(new_x)

but I am getting:

ValueError: A value in x_new is below the interpolation range.

in interpolate.py

Any help would be appreciated.

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
Hellfish
  • 1,685
  • 3
  • 12
  • 10

3 Answers3

19

From the scipy documentation on scipy.interpolate.interp1d:

scipy.interpolate.interp1d(x, y, kind='linear', axis=-1, copy=True, bounds_error=True, fill_value=np.nan)

x : array_like. A 1-D array of monotonically increasing real values.

...

The problem is that the x values are not monotonically increasing. In fact they are monotonically decreasing. Let me know if this works and if its still the computation you are looking for.:

import numpy as np
import scipy as sp
from scipy.interpolate import interp1d

x1 = sorted([1., 0.88, 0.67, 0.50, 0.35, 0.27, 0.18, 0.11, 0.08, 0.04, 0.04, 0.02])
y1 = [0., 13.99, 27.99, 41.98, 55.98, 69.97, 83.97, 97.97, 111.96, 125.96, 139.95, 153.95]

new_length = 25
new_x = np.linspace(x.min(), x.max(), new_length)
new_y = sp.interpolate.interp1d(x, y, kind='cubic')(new_x)
Community
  • 1
  • 1
ciferkey
  • 2,064
  • 3
  • 20
  • 28
  • 4
    Instead of `sorted()` you could have just used `x1.reverse()` and `y1.reverse()`. – gotgenes Aug 07 '12 at 19:08
  • 9
    In this example the x1,y1 pairs are broken by sorting ONLY the x1 array. The y1 array should be shuffled the same way as the x1 array is. – Vasco Apr 28 '15 at 11:50
14

You can get this in the following way:

import numpy as np
import scipy as sp
from scipy.interpolate import interp1d

x1 = [1., 0.88,  0.67,  0.50,  0.35,  0.27, 0.18,  0.11,  0.08,  0.04,  0.04,  0.02]
y1 = [0., 13.99, 27.99, 41.98, 55.98, 69.97, 83.97, 97.97, 111.96, 125.96, 139.95, 153.95]

# Combine lists into list of tuples
points = zip(x1, y1)

# Sort list of tuples by x-value
points = sorted(points, key=lambda point: point[0])

# Split list of tuples into two list of x values any y values
x1, y1 = zip(*points)

new_length = 25
new_x = np.linspace(min(x1), max(x1), new_length)
new_y = sp.interpolate.interp1d(x1, y1, kind='cubic')(new_x)
Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
  • 3
    Using above code, I'm getting this error in the last line, using Python 3.6: `ValueError: Expect x to be a 1-D sorted array_like.` – K.-Michael Aye Aug 14 '17 at 06:37
  • @K.-MichaelAye For me, it works fine with Python 2.7 and Python 3.5. I have numpy 1.11 and scipy 0.17.0. Which versions do you use? – Martin Thoma Aug 14 '17 at 06:54
  • Indeed with Python 3.5 numpy 1.11.3 and scipy 0.17.1 it works. It also works with scipy 0.18.1 and numpy 1.11.3, but then breaks with scipy 0.19.1. Apparently, `interp1d` is now deprecated anyway. – K.-Michael Aye Aug 14 '17 at 17:25
  • @K.-MichaelAye: thanks. [`interp1d`](https://docs.scipy.org/doc/scipy/reference/generated/scipy.interpolate.interp1d.html) does not seem to be deprecated, but indeed it fails at scipy 0.19, and works with 0.18.1. – Adobe Feb 21 '18 at 19:18
  • 1
    See discussion here, interp1d is now UnivariateSpline https://github.com/scipy/scipy/issues/4304 – K.-Michael Aye Feb 21 '18 at 23:13
0

I've just got the above error and fixed it with remove duplicated value in the X and Y array.

x = np.sort(np.array([0, .2, .2, .4, .6, .9]))
y = np.sort(np.sort(np.array([0, .1, .06, .11, .25, .55]))

⬇ Change 0.2 to 0.3 or any number.

x = np.sort(np.array([0, .2, .3, .4, .6, .9]))
y = np.sort(np.sort(np.array([0, .1, .06, .11, .25, .55]))