Reputation: 503
I have lists with tuples. Is there any way that I can interpolate the graph so that I can find the x when the y equal to specific number?
For example, this is the list I have: (The form: (x, y))
testList = [[(0.0, 0.16321045084221542), (0.5, 0.14992804419926076), (1.0, 0.11065532637895514), (1.5, 0.04708907515862726), (2.0, -0.03802861479205555), (2.5, -0.14102850232363529), (3.0, -0.25746055864004425), (3.5, -0.3822538828249663), (4.0, -0.5098763060056799), (4.5, -0.6344823989838556), (5.0, -0.750042167345144), (5.5, -0.8504464361832059), (6.0, -0.9295881546855232), (6.5, -0.9814212354546451), (7.0, -1.0), (7.5, -0.9795029369940005), (8.0, -0.9142444982515833), (8.5, -0.7986782837636315), (9.0, -0.6273943971548426), (9.5, -0.3951131313722883), (10.0, -0.0966765630073454), (10.5, 0.27296085997528263), (11.0, 0.718742042145311), (11.5, 1.2455168707452469), (12.0, 1.8580515496188488), (12.5, 2.5610375682282385), (13.0, 3.359100318716231)],
[(0.0, 3.945199007815406), (0.5, 3.9143355111694476), (1.0, 3.8226370706824335), (1.5, 3.672732794584979), (2.0, 3.4688535859541165), (2.5, 3.2166250107987775), (3.0, 2.922811878989832), (3.5, 2.5950409577289504), (4.0, 2.24152674173692), (4.5, 1.8708203973719262), (5.0, 1.4915954141769467), (5.5, 1.1124766759626983), (6.0, 0.7419137749030704), (6.5, 0.38809507884546), (7.0, 0.05889647076017157), (7.5, -0.23814239507555024), (8.0, -0.49582141693684445), (8.5, -0.7072692740017781), (9.0, -0.8659237611855242), (9.5, -0.9655072278443139), (10.0, -1.0), (10.5, -0.9636137216085844), (11.0, -0.8507658078900049), (11.5, -0.6560556545698524), (12.0, -0.37424286410281404), (12.5, -0.00022749998495563695), (13.0, 0.47096776983628086)]]
After plotting, it results in:
I am trying to get the x indexs when y indexs are equal to -1, and 0.
Like this: result = [[(7.0, -1.0), (x1, 0.0), (x2, 0.0)], [(10, -1.0), (x3, 0.0), (x4, 0.0)]]
Upvotes: 0
Views: 844
Reputation: 19810
If your functions were monotone I would agree with the other solution, but since you are looking at more than one location, I think fitting a spline and using the .roots()
method is more reliable:
import numpy as np
from scipy.interpolate import InterpolatedUnivariateSpline
def find_x_at_y_target(x, y, y_target):
"""Find the corresponding x value at which a smooth-ish function sampled
at x, y becomes equal to y_target via spline interpolation."""
spline = InterpolatedUnivariateSpline(x, y - y_target)
return spline.roots()
def merge(roots, tol=1e-5):
"""Remove duplicate roots which are closer to each other than tol"""
result = []
for root in roots:
if not result or np.abs(result[-1] - root) > tol:
result.append(root)
return result
result = []
for test in testList:
testresult = []
result.append(testresult)
x, y = np.array(test).T
for y_target in [0.0, -1.0]:
found_xs = find_x_at_y_target(x, y, y_target)
for found_x in merge(found_xs):
testresult.append((found_x, y_target))
For your test data this results in
[[(1.7907321051459066, 0.0),
(10.1408055626703, 0.0),
(6.999999134927593, -1.0)],
[(7.094611008491239, 0.0),
(12.500269673618083, 0.0),
(9.999999999995387, -1.0)]]
Notice that in this case the spline method returns two roots near -1, which requires some additional processing.
Upvotes: 2
Reputation: 3855
Using scipy.interpolate.interp1d
you can create the inverse function of x = f(y) and use this interpolation function (which by default uses linear interpolation, but has other modes) in order to find the x-coordinate corresponding to y = -1
from scipy import interpolate
testList = [[(0.0, 0.16321045084221542), (0.5, 0.14992804419926076), (1.0, 0.11065532637895514), (1.5, 0.04708907515862726), (2.0, -0.03802861479205555), (2.5, -0.14102850232363529), (3.0, -0.25746055864004425), (3.5, -0.3822538828249663), (4.0, -0.5098763060056799), (4.5, -0.6344823989838556), (5.0, -0.750042167345144), (5.5, -0.8504464361832059), (6.0, -0.9295881546855232), (6.5, -0.9814212354546451), (7.0, -1.0), (7.5, -0.9795029369940005), (8.0, -0.9142444982515833), (8.5, -0.7986782837636315), (9.0, -0.6273943971548426), (9.5, -0.3951131313722883), (10.0, -0.0966765630073454), (10.5, 0.27296085997528263), (11.0, 0.718742042145311), (11.5, 1.2455168707452469), (12.0, 1.8580515496188488), (12.5, 2.5610375682282385), (13.0, 3.359100318716231)],
[(0.0, 3.945199007815406), (0.5, 3.9143355111694476), (1.0, 3.8226370706824335), (1.5, 3.672732794584979), (2.0, 3.4688535859541165), (2.5, 3.2166250107987775), (3.0, 2.922811878989832), (3.5, 2.5950409577289504), (4.0, 2.24152674173692), (4.5, 1.8708203973719262), (5.0, 1.4915954141769467), (5.5, 1.1124766759626983), (6.0, 0.7419137749030704), (6.5, 0.38809507884546), (7.0, 0.05889647076017157), (7.5, -0.23814239507555024), (8.0, -0.49582141693684445), (8.5, -0.7072692740017781), (9.0, -0.8659237611855242), (9.5, -0.9655072278443139), (10.0, -1.0), (10.5, -0.9636137216085844), (11.0, -0.8507658078900049), (11.5, -0.6560556545698524), (12.0, -0.37424286410281404), (12.5, -0.00022749998495563695), (13.0, 0.47096776983628086)]]
x1 = [c[0] for c in testList[0]]
y1 = [c[1] for c in testList[0]]
x2 = [c[0] for c in testList[1]]
y2 = [c[1] for c in testList[1]]
f1 = interpolate.interp1d(y1, x1)
f2 = interpolate.interp1d(y2, x2)
print(f1(-1), f2(-1))
Upvotes: 2