pythonscipycurve-fittingsplinecubic-spline

Python gradient matching spline


I am trying to fill in the gaps between two curves using a spline in Python. I would like my new line to match the gradient of the original curves at each end. The problem arises from needing monotonically increasing x-values in scipy.interpolate spline routines. The code below is an example of what I am dealing with. Two curves in blue ('line 1' and 'line 2') are what I've got and (something like) what I would want out of spline is shown by the line labelled 'Wanted'.

Does anyone have any suggestions how I could go about this?

import numpy as np
import matplotlib.pyplot as plt
import scipy.interpolate as interp

line1_x = np.array([4.0e8, 4.7e8, 5.5e8, 6.6e8, 8.0e8, 1.0e9, 1.4e9, 2.0e9, 3.6e9, 
                    9.5e9])
line1_y = np.array([5500., 5000., 4500., 4000., 3500., 3000., 2500., 2000., 1500.,
                    1000.])
                
line2_x = np.array([1.010e10, 1.060e10, 1.081e10, 1.084e10, 1.076e10, 1.064e10, 
                    1.055e10, 1.050e10, 1.051e10, 1.057e10, 1.067e10, 1.079e10, 
                    1.091e10, 1.102e10, 1.112e10])
line2_y = np.array([350., 361., 372., 385., 395., 407., 418., 430., 442., 454., 
                    466., 478., 490., 503., 515.])

desired_x = np.array([1.112e10, 1.117e10, 1.121e10, 1.116e10, 1.087e10, 1.027e10, 
                      9.869e9, 9.5e9])
desired_y = np.array([515., 536., 575., 645., 748., 891., 962., 1000.])

plt.plot(line1_x, line1_y, 'b-', label='Line 1')
plt.plot(line2_x, line2_y, 'b-', label='Line 2')
plt.plot(desired_x, desired_y, 'r--', label='Wanted')
plt.legend(loc=0)

Spline Fig Example


Solution

  • I haven't been able to work out how to get around the need for x to be increasing. So I took a slightly "cheating" option instead. Since my y is always increasing I can just use the standard scipy.interpolate spline routines to get the desired output.

    The bit of code that needs adding to my example in the question to make it work is:

    x = np.concatenate((line1_x, line2_x))
    y = np.concatenate((line1_y, line2_y))
    order = np.argsort(y)
    
    spline_fit = interp.UnivariateSpline(y[order], x[order])
    y_points = np.linspace(515, 1000, 20)
    
    plt.plot(spline_fit(y_points), y_points, 'k--', label='Fit')
    

    Which gives the desired result: enter image description here