I am constructing a spine that interpolates well some data I have and I want to store this in a database. I thought that this would be straightforward since I can just take the knots and the coefficients and just create a new spline with them. However, this goes horribly wrong. Here is a minimal (non) working example.
import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate
xs = np.linspace(0,2,101)
ys = xs*np.cos(2*np.pi*xs)
knotNumber = 9
knots = np.linspace(0,2,knotNumber)[1:-1]
spline = interpolate.LSQUnivariateSpline(xs,ys,knots,k=3)
re_spline = interpolate.BSpline(spline.get_knots(),spline.get_coeffs(),3)
sp_ys = spline(xs)
re_ys = re_spline(xs)
plt.plot(xs, ys, '-', color='black');
plt.plot(xs, sp_ys, '-', color='blue');
plt.plot(xs, re_ys, '-', color='red');
This results to the following figure:
As you can see the LSQUnivariateSpline
blue curve covers completely the black. The red curve that comes from the spline I created seems completely unrelated.
Is there something obvious I am missing here? How can I reconstruct the spline?
BSpline
needs k
extra knots at the start and end (the fixed points); different than (LSQ
)`UnivariateSpline.
I found this by looking at the result of
interpolate.splrep(xs, ys, k=3, task=-1, t=knots)
which shows 3 extra zeros at the start of the outputted knots, and 3 extra twos at the end:
[0. 0. 0. 0. 0.25 0.5 0.75 1. 1.25 1.5 1.75 2. 2. 2. 2. ]
.
(The amount of extra endpoints obviously depends on the degree.)
With that given, the following should work:
xs = np.linspace(0,2,101)
ys = xs*np.cos(2*np.pi*xs)
k = 3
knotNumber = 9
knots = np.linspace(0,2,knotNumber)
spline = interpolate.LSQUnivariateSpline(xs, ys, knots[1:-1], k=k)
bknots = np.array(k * [knots[0]] + spline.get_knots().tolist() + k * [knots[-1]])
re_spline = interpolate.BSpline(bknots, spline.get_coeffs(), k)
sp_ys = spline(xs)
re_ys = re_spline(xs)
(Or with any other, prettier, way to prepend and append the extra knots to spline.get_knots()
.)