Spline Interpolation with Python
Asked Answered
S

3

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.

Seiber answered 7/8, 2012 at 18:18 Comment(2)
I tried running your code and got name 'np' is not defined. Is this your whole program?Vaseline
No, you need to import: numpy as np, scipy as sp, scipy.interpolateSeiber
G
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)
Gothart answered 7/8, 2012 at 18:47 Comment(2)
Instead of sorted() you could have just used x1.reverse() and y1.reverse().Entrails
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.Tailorbird
L
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)
Lagunas answered 9/6, 2014 at 15:18 Comment(5)
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.Oops
@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?Lagunas
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.Oops
@K.-MichaelAye: thanks. interp1d does not seem to be deprecated, but indeed it fails at scipy 0.19, and works with 0.18.1.Sealey
See discussion here, interp1d is now UnivariateSpline github.com/scipy/scipy/issues/4304Oops
P
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]))
Paterson answered 31/10, 2020 at 20:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.