Skip to content
Advertisement

Pulling x-values of spline integer y-values?

I have the given sample data and interpolated spline:

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

x = [0.1, 1.5, 2.3, 5.5, 6.7, 7]
y = [5, 4, 5, 2, 2, 3]
s = interpolate.UnivariateSpline(x, y, s=0)

xs = np.linspace(min(x), max(x), 10000) #values for x axis
ys = s(xs)

plt.figure()
plt.plot(xs, ys, label='spline')
plt.plot(x, y, 'x', label='collected data')
plt.legend()

enter image description here

I would like to pull the x values that correspond to the integer y values of the spline, but am not sure how to do this. I assume I will be using np.where() and have tried (to no avail):

root_index = np.where(ys == ys.round())

Advertisement

Answer

You could use the find_roots function from this post to find the exact interpolated x-values:

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

def find_roots(x, y):
    s = np.abs(np.diff(np.sign(y))).astype(bool)
    return x[:-1][s] + np.diff(x)[s] / (np.abs(y[1:][s] / y[:-1][s]) + 1)

x = [0.1, 1.5, 2.3, 5.5, 6.7, 7]
y = [5, 4, 5, 2, 2, 3]
s = interpolate.UnivariateSpline(x, y, s=0)

xs = np.linspace(min(x), max(x), 500)  # values for x axis
ys = s(xs)

plt.figure()
plt.plot(xs, ys, label='spline')

for y0 in range(0, 7):
    r = find_roots(xs, ys - y0)
    if len(r) > 0:
        plt.scatter(r, np.repeat(y0, len(r)), label=f'y0 = {y0}')
        for ri in r:
            plt.text(ri, y0, f'  {ri:.3f}', ha='left', va='center')
plt.legend()
plt.xlim(min(x) - 0.2, max(x) + 1)
plt.show()

example plot

PS: with much less points for the x’s, e.g. xs = np.linspace(min(x), max(x), 50), the curve would look a bit bumpy, and the interpolation would be slightly different:

less points

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement