18

I'm writing a python script to interpolate a given set of points with splines. The points are defined by their [x, y] coordinates.

I tried to use this code:

x = np.array([23, 24, 24, 25, 25])
y = np.array([13, 12, 13, 12, 13])
tck, u = scipy.interpolate.splprep([x,y], s=0)
unew = np.arange(0, 1.00, 0.005)
out = scipy.interpolate.splev(unew, tck) 

which gives me a curve like this:

Bad Interpolation

However, I need to have a smooth closed curve - on the picture above the derivatives at one of the points are obviously not the same. How can I achieve this?

ali_m
  • 71,714
  • 23
  • 223
  • 298
sooobus
  • 841
  • 1
  • 9
  • 22

1 Answers1

26

Your closed path can be considered as a parametric curve, x=f(u), y=g(u) where u is distance along the curve, bounded on the interval [0, 1). You can use scipy.interpolate.splprep with per=True to treat your x and y points as periodic, then evaluate the fitted splines using scipy.interpolate.splev:

import numpy as np
from scipy import interpolate
from matplotlib import pyplot as plt

x = np.array([23, 24, 24, 25, 25])
y = np.array([13, 12, 13, 12, 13])

# append the starting x,y coordinates
x = np.r_[x, x[0]]
y = np.r_[y, y[0]]

# fit splines to x=f(u) and y=g(u), treating both as periodic. also note that s=0
# is needed in order to force the spline fit to pass through all the input points.
tck, u = interpolate.splprep([x, y], s=0, per=True)

# evaluate the spline fits for 1000 evenly spaced distance values
xi, yi = interpolate.splev(np.linspace(0, 1, 1000), tck)

# plot the result
fig, ax = plt.subplots(1, 1)
ax.plot(x, y, 'or')
ax.plot(xi, yi, '-b')

enter image description here

ali_m
  • 71,714
  • 23
  • 223
  • 298
  • 1
    It works perfect if I don't append the starting coordinates. – sooobus Nov 27 '15 at 18:48
  • Really? Doesn't work for me - I get a 'figure of 8' if I don't append the starting coordinates. The docs for the `per` argument also say *"If non-zero, data points are considered periodic with period x[m-1] - x[0] and a smooth periodic spline approximation is returned. Values of y[m-1] and w[m-1] are not used."*, which suggests to me that it will ignore the last coordinates in `x` and `y`. – ali_m Nov 27 '15 at 18:55
  • I get this problem if I append coordinates: https://mail.scipy.org/pipermail/scipy-user/2007-September/013650.html – sooobus Nov 27 '15 at 18:58
  • 1
    Weird. Maybe it's version-related? All I can say is that appending the start coordinates works perfectly for me using scipy 0.14.1 and 0.16.0, whereas not appending them results in a figure-of-eight curve that does not pass through the point at (25, 13). Perhaps it has something to do with the extra point in your plot at (22, 13)? – ali_m Nov 27 '15 at 19:03
  • @ali_m would it be possible to evaluate the spline fits for `n` specific values (instead of 1000 evenly spaced distance values)? – AJMA Apr 19 '19 at 15:40