Example 2. Spline Approximation with SciPy


import numpy as np
import scipy.interpolate as si
import matplotlib.pyplot as plt
from string import split, join

def readXY(filepath="./XYdata.txt"):
    with open(filepath, "r") as data:
        X = []
        Y = []
        for line in data:
            splitline = split(line)
            try:
                X.append(float(splitline[0]))
                Y.append(float(splitline[1]))
            except:
                pass
    return X, Y

def getControlPoints(knots, k):
    n = len(knots) - 1 - k
    cx = np.zeros(n)
    for i in range(n):
        tsum = 0
        for j in range(1,k + 1):
            tsum += knots[i+j]
        cx[i] = float(tsum)/k
    return cx

def plotSplineFunction(title="Spline Function", offset_x=0.5, offset_y=0.05):
    plt.plot(coeffs_x, coeffs_y, 'go-')
    plt.plot(x, y, 'ro')
    plt.plot(xP, yP, lw=2)
    plt.plot(knots, knotsy, 'gs') # ,markersize=10
    plt.axis([xmin-offset_x, xmax+offset_x, ymin-offset_y, ymax+offset_y])
    plt.grid(True)
    plt.title(title)
    plt.show()

def findLSQSplineRep():
    global knots, knots_full, coeffs_y, coeffs_x, yP, knotsy
    lsqspline = si.LSQUnivariateSpline(x, y, knots, k=k, w=w)
    knots = lsqspline.get_knots()
    coeffs_y = lsqspline.get_coeffs()
    yP = lsqspline(xP)
    knotsy = lsqspline(knots)
    knots_full = np.concatenate(([knots[0]]*k, knots, [knots[-1]]*k))
    coeffs_x = getControlPoints(knots_full, k)

def findSmoothedSplineRep(s=0.005):
    global knots, knots_full, coeffs_y, coeffs_x, yP, knotsy
    spline = si.UnivariateSpline( x, y, k=k , s=s, w=w)
    knots = spline.get_knots()
    coeffs_y = spline.get_coeffs()
    yP = spline(xP)
    knotsy = spline(knots)
    knots_full = np.concatenate(([knots[0]]*k, knots, [knots[-1]]*k))
    coeffs_x = getControlPoints(knots_full, k)

##### LOAD DATA POINTS #####

x, y = readXY("./data_charts/cy_f004.txt")

# print "x:", x
# print "y:", y

### set variables
nsample = 100
nknot = 3
k = 3
num_points = len(x)
xmin, xmax = min(x), max(x) 
ymin, ymax = min(y), max(y)
xP = np.linspace(x[0], x[-1], nsample)
# xP = np.linspace( x[0]-2, x[-1]+2, nsample )

plt.plot(x, y, 'ro')
plt.axis([xmin-0.5, xmax+0.5, ymin-0.05, ymax+0.05])
plt.grid(True)
plt.title("Data points")
plt.show()

### define weight vector to push further approximations stick to end points
wend = 3
w = [wend] + [1]*(num_points-2) + [wend]

##### FIND LSQ SPLINE REPRESENTATION  #####

### try with uniform knot vector

knot_offset = (xmax - xmin)/(nknot + 1)
knots = np.linspace(knot_offset, xmax-knot_offset, nknot)

findLSQSplineRep()
plotSplineFunction(title="LSQ spline function with uniform knot vector", offset_x=1.)

### manually select best fitting non-uniform knot vector

knots = [1.2, 1.85, 2.1, 2.4, 2.6] # !!
knots = [1.2, 1.85, 2.3, 2.6, 3.2] # !
knots = [1.2, 1.85, 2.0, 2.7, 3.2] # !!!
knots = [1.2, 1.85, 2.0, 2.8, 3.5] # !!!!

findLSQSplineRep()
plotSplineFunction(title="LSQ spline function with manual selected non-uniform knot vector", offset_x=1.)

#####  FIND SMOOTHED SPLINE REPRESENTATION   #####

findSmoothedSplineRep(s=0.1)
plotSplineFunction(title="Smoothed spline function s=0.1")
# print "s=0.1, knots:", knots
# findSmoothedSplineRep(s=0)
# plotSplineFunction(title = "Polynomial spline interpolation")
# print "s=0, knots:", knots
findSmoothedSplineRep()
plotSplineFunction(title="Smoothed spline function s=0.005")
# print "s=0.05, knots:", knots

#####   MANUALLY SELECT BEST_FITTING CONTROL POINTS   #####

### try to comment next two rows to look at the original smoothed spline curve after parametrization
coeffs_x = [x[0], 1.1, 1.7, 2.16, 3.1, 3.0, x[-1]]
coeffs_y = [y[0], 0.11, 0.17, 0.32, 0.27, 0.19, y[-1]]

#####   PARAMETRIC SPLINE REPRESENTATION   #####

### norm knot vector to number of points

num_knots = len(knots_full)
ka = (knots_full[-1] - knots_full[0])/(num_points)
knotsp = np.zeros(num_knots)
for i in range(num_knots):
 knotsp[i] = num_points-((knots_full[-1] - knots_full[i]))/ka
# print "knotsp:", knotsp

### find parametric spline representation based on control points coordinates (coeffs_x, coeffs_y)

tckX = knotsp, coeffs_x, k
tckY = knotsp, coeffs_y, k

splineX = si.UnivariateSpline._from_tck(tckX)
splineY = si.UnivariateSpline._from_tck(tckY)

coeffs_p = getControlPoints(knotsp, k)
tP = np.linspace(0, num_points, 100)
# tP = np.linspace(-20,  num_points+20, 100)
xP = splineX(tP)
yP = splineY(tP)

#####   PLOT PARAMETRIC SPLINE CURVE   #####

offset_x = (xmax-xmin)*0.05
offset_y = (ymax-ymin)*0.1
ct = 0.5
tadd = 0.5

# offset_x = (xmax-xmin)*0.2
# offset_y = (ymax-ymin)*0.2
# ct = 0.7
# tadd = 1.0

knotpoints_y = [ymin-offset_y*ct]*len(knotsp)
knotpoints_x = [xmin-offset_x*ct]*len(knotsp)

fig = plt.figure()

ax = fig.add_subplot(224)
ax.grid(True)
plt.plot(coeffs_x, coeffs_p, '-og')
plt.plot(xP, tP, 'r', lw=2)
plt.plot(knotpoints_x, knotsp, '>', ms=6, color='black')
plt.ylim([-tadd, num_points+tadd])
plt.xlim([xmin - offset_x, xmax + offset_x])
plt.ylabel('t', rotation=0,  labelpad=20, fontweight='bold', fontsize=14)
plt.xlabel('x', labelpad=5, fontweight='bold', fontsize=14)
ax.invert_yaxis()
plt.title('Spline function x(t)')

ax = fig.add_subplot(221)
ax.grid(True)
plt.plot(coeffs_p, coeffs_y, '-og')
plt.plot(tP, yP, 'r', lw=2)
plt.plot(knotsp,knotpoints_y, '^', ms=6, color='black')
plt.xlim([-tadd, num_points+tadd])
plt.ylim([ymin - offset_y, ymax + offset_y])
plt.ylabel('y', labelpad=20, rotation=0, fontweight='bold', fontsize=14)
plt.xlabel('t', labelpad=10, fontweight='bold', fontsize=14)
ax.invert_xaxis()
plt.title('Spline function y(t)')

ax = fig.add_subplot(222)
ax.grid(True)
plt.plot(x, y, 'ro')
plt.plot(coeffs_x, coeffs_y, '-og')
plt.plot(xP, yP, 'b', lw=2.5)
plt.xlim([xmin - offset_x, xmax + offset_x])
plt.ylim([ymin - offset_y, ymax + offset_y])
plt.title('Spline curve f(x(t), y(t))')

plt.show()

2023 © Vadym Pasko