Joanne
Joanne

Reputation: 503

Interpolation from data plotted with tuples in lists using Python

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: enter image description here

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

Answers (2)

chthonicdaemon
chthonicdaemon

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

awarrier99
awarrier99

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

Related Questions