Intersection of two graphs in Python, find the x value Intersection of two graphs in Python, find the x value python python

Intersection of two graphs in Python, find the x value


You can use np.sign in combination with np.diff and np.argwhere to obtain the indices of points where the lines cross (in this case, the points are [ 0, 149, 331, 448, 664, 743]):

import numpy as npimport matplotlib.pyplot as pltx = np.arange(0, 1000)f = np.arange(0, 1000)g = np.sin(np.arange(0, 10, 0.01) * 2) * 1000plt.plot(x, f, '-')plt.plot(x, g, '-')idx = np.argwhere(np.diff(np.sign(f - g))).flatten()plt.plot(x[idx], f[idx], 'ro')plt.show()

plot of intersection points

First it calculates f - g and the corresponding signs using np.sign. Applying np.diff reveals all the positions, where the sign changes (e.g. the lines cross). Using np.argwhere gives us the exact indices.


For those who are using or open to use the Shapely library for geometry-related computations, getting the intersection will be much easier. You just have to construct LineString from each line and get their intersection as follows:

import numpy as npimport matplotlib.pyplot as pltfrom shapely.geometry import LineStringx = np.arange(0, 1000)f = np.arange(0, 1000)g = np.sin(np.arange(0, 10, 0.01) * 2) * 1000plt.plot(x, f)plt.plot(x, g)first_line = LineString(np.column_stack((x, f)))second_line = LineString(np.column_stack((x, g)))intersection = first_line.intersection(second_line)if intersection.geom_type == 'MultiPoint':    plt.plot(*LineString(intersection).xy, 'o')elif intersection.geom_type == 'Point':    plt.plot(*intersection.xy, 'o')

enter image description here

And to get the x and y values as NumPy arrays you would just write:

x, y = LineString(intersection).xy# x: array('d', [0.0, 149.5724669847373, 331.02906176584617, 448.01182730277833, 664.6733061190541, 743.4822641140581])# y: array('d', [0.0, 149.5724669847373, 331.02906176584617, 448.01182730277833, 664.6733061190541, 743.4822641140581])

or if an intersection is only one point:

x, y = intersection.xy


Here's a solution which:

  • Works with N-dimensional data
  • Uses Euclidean distance rather than merely finding cross-overs in the y-axis
  • Is more efficient with lots of data (it queries a KD-tree, which should query in logarathmic time instead of linear time).
  • You can change the distance_upper_bound in the KD-tree query to define how close is close enough.
  • You can query the KD-tree with many points at the same time, if needed. Note: if you need to query thousands of points at once, you can get dramatic performance increases by querying the KD-tree with another KD-tree.

enter image description here

import numpy as npimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d import Axes3Dfrom scipy.spatial import cKDTreefrom scipy import interpolatefig = plt.figure()ax = fig.add_axes([0, 0, 1, 1], projection='3d')ax.axis('off')def upsample_coords(coord_list):    # s is smoothness, set to zero    # k is degree of the spline. setting to 1 for linear spline    tck, u = interpolate.splprep(coord_list, k=1, s=0.0)    upsampled_coords = interpolate.splev(np.linspace(0, 1, 100), tck)    return upsampled_coords# target linex_targ = [1, 2, 3, 4, 5, 6, 7, 8]y_targ = [20, 100, 50, 120, 55, 240, 50, 25]z_targ = [20, 100, 50, 120, 55, 240, 50, 25]targ_upsampled = upsample_coords([x_targ, y_targ, z_targ])targ_coords = np.column_stack(targ_upsampled)# KD-tree for nearest neighbor searchtarg_kdtree = cKDTree(targ_coords)# line twox2 = [3,4,5,6,7,8,9]y2 = [25,35,14,67,88,44,120]z2 = [25,35,14,67,88,44,120]l2_upsampled = upsample_coords([x2, y2, z2])l2_coords = np.column_stack(l2_upsampled)# plot both linesax.plot(x_targ, y_targ, z_targ, color='black', linewidth=0.5)ax.plot(x2, y2, z2, color='darkgreen', linewidth=0.5)# find intersectionsfor i in range(len(l2_coords)):    if i == 0:  # skip first, there is no previous point        continue    distance, close_index = targ_kdtree.query(l2_coords[i], distance_upper_bound=.5)    # strangely, points infinitely far away are somehow within the upper bound    if np.isinf(distance):        continue    # plot ground truth that was activated    _x, _y, _z = targ_kdtree.data[close_index]    ax.scatter(_x, _y, _z, 'gx')    _x2, _y2, _z2 = l2_coords[i]    ax.scatter(_x2, _y2, _z2, 'rx')  # Plot the cross pointplt.show()