Search code examples
pythonscipyinterpolationspline

Creating an incremental smooth spline curve instead of non-uniform increments in python


I am trying to smoothen my data using spline - which is basically cumulative percentile on the y-axis and a reference point they refer to on the x-axis. I get most part of it correct, however, the challenge I am facing is my y axis is increasing in a non linear way - as seen int he spline plot below- y-axis value keep increasing and decreasing, instead of just increasing.

I still want a smooth curve but want y-axis to increase with the x-axis - i.e. each subsequent y-axis point should be equal or a slight increment in value from the previous value, as opposed to increasing and the decreasing later.

Reproducible code:

import pandas as pd 
import numpy as np 
from scipy.interpolate import make_interp_spline 
import matplotlib.pyplot as plt 
from matplotlib.pyplot import figure 

percentile_block_df = pd.DataFrame({ 
'x' : [0.5,100.5,200.5,400.5,800.5,900.5,1000.5], 
'percentile' : [0.0001,0.01,0.065,0.85,0.99,0.9973,0.9999] 
})

figure(figsize=(8, 6), dpi=80) 
y = percentile_block_df.percentile 
x = percentile_block_df.x 

X_Y_Spline = make_interp_spline(x, y) 

# Returns evenly spaced numbers 
# over a specified interval. 
X_ = np.linspace(x.min(), x.max(), 1000)
Y_ = X_Y_Spline(X_)

figure(figsize=(18, 6), dpi=80)
plt.subplot(1, 2, 1) # row 1, col 2 index 1
plt.plot(x, y,"ro")
plt.plot(x, y)
plt.title("Original")
plt.xlabel('X')
plt.ylabel('Percentile ')

plt.subplot(1, 2, 2) # index 2
plt.plot(x, y,"ro")
plt.plot(X_, Y_,"green")
plt.title("Spline Plot")
plt.xlabel('X')
plt.ylabel('Percentile ')

plt.show()

See Chart


Solution

  • What you are looking for is "monotonicity preserving interpolation". A quick search shows that scipy.interpolate.PchipInterpolator does just that. Here is the result for your example when simply plugging in from scipy.interpolate import PchipInterpolator instead of from scipy.interpolate import make_interp_spline.

    enter image description here

    Whether or not that's appropriate depends of course on your specific requirements for the interpolation. I encourage you to research the other options which are out there.

    Similar question: