如何找到两个图的交点

2025-02-11 09:51:00
admin
原创
55
摘要:问题描述:令 0 <= x <= 1。我有两列f和,g长度分别为 5000。现在我绘制:plt.plot(x, f, '-') plt.plot(x, g, '*') 我想找到曲线相交的点“x”。我不想找到 f 和 g 的交点。我可以用以下方法轻松完成:set(f) & set(g) 解决...

问题描述:

令 0 <= x <= 1。我有两列f和,g长度分别为 5000。现在我绘制:

plt.plot(x, f, '-')
plt.plot(x, g, '*')

我想找到曲线相交的点“x”。我不想找到 f 和 g 的交点。我可以用以下方法轻松完成:

set(f) & set(g)

解决方案 1:

您可以np.signnp.diff和结合使用np.argwhere来获取线交叉点的索引(在本例中,点是[ 0, 149, 331, 448, 664, 743]):

import numpy as np
import matplotlib.pyplot as plt

x = np.arange(0, 1000)
f = np.arange(0, 1000)
g = np.sin(np.arange(0, 10, 0.01) * 2) * 1000

plt.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()

交点图

首先,它f - g使用 计算和相应的符号np.sign。应用np.diff揭示符号发生变化的所有位置(例如线交叉)。使用np.argwhere为我们提供精确的索引。

解决方案 2:

对于那些正在使用或愿意使用Shapely库进行几何相关计算的人来说,获取交点将更加容易。你只需要从LineString每一行构建并获取它们,intersection如下所示:

import numpy as np
import matplotlib.pyplot as plt
from shapely.geometry import LineString

x = np.arange(0, 1000)
f = np.arange(0, 1000)
g = np.sin(np.arange(0, 10, 0.01) * 2) * 1000

plt.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')

在此处输入图片描述

要将xy值作为 NumPy 数组获取,只需编写:

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])

或者如果交点只有一个点:

x, y = intersection.xy

解决方案 3:

这是一个解决方案:

  • 处理 N 维数据

  • 使用欧几里得距离,而不仅仅是寻找 y 轴上的交叉点

  • 对于大量数据来说效率更高(它查询KD 树,查询时间是指数级的而不是线性的)。

  • 您可以更改distance_upper_boundKD 树查询来定义多接近才算足够接近。

  • 如果需要,您可以同时使用许多点查询 KD 树。注意:如果您需要一次查询数千个点,则可以通过使用另一个 KD 树查询 KD 树来显著提高性能。

在此处输入图片描述

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial import cKDTree
from scipy import interpolate

fig = 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 line
x_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 search
targ_kdtree = cKDTree(targ_coords)

# line two
x2 = [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 lines
ax.plot(x_targ, y_targ, z_targ, color='black', linewidth=0.5)
ax.plot(x2, y2, z2, color='darkgreen', linewidth=0.5)

# find intersections
for 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 point


plt.show()

解决方案 4:

好吧,我正在寻找一个 matplotlib,用于绘制两条大小不同且 x 值不同的曲线。以下是我得到的:

import numpy as np
import matplotlib.pyplot as plt
import sys

fig = plt.figure()
ax = fig.add_subplot(111)

# x1 = [1,2,3,4,5,6,7,8]
# y1 = [20,100,50,120,55,240,50,25]
# x2 = [3,4,5,6,7,8,9]
# y2 = [25,200,14,67,88,44,120]

x1=[1.4,2.1,3,5.9,8,9,12,15]
y1=[2.3,3.1,1,3.9,8,9,11,9]
x2=[1,2,3,4,6,8,9,12,14]
y2=[4,12,7,1,6.3,7,5,6,11]

ax.plot(x1, y1, color='lightblue',linewidth=3, marker='s')
ax.plot(x2, y2, color='darkgreen', marker='^')

y_lists = y1[:]
y_lists.extend(y2)
y_dist = max(y_lists)/200.0

x_lists = x1[:]
x_lists.extend(x2)  
x_dist = max(x_lists)/900.0
division = 1000
x_begin = min(x1[0], x2[0])     # 3
x_end = max(x1[-1], x2[-1])     # 8

points1 = [t for t in zip(x1, y1) if x_begin<=t[0]<=x_end]  # [(3, 50), (4, 120), (5, 55), (6, 240), (7, 50), (8, 25)]
points2 = [t for t in zip(x2, y2) if x_begin<=t[0]<=x_end]  # [(3, 25), (4, 35), (5, 14), (6, 67), (7, 88), (8, 44)]
# print points1
# print points2

x_axis = np.linspace(x_begin, x_end, division)
idx = 0
id_px1 = 0
id_px2 = 0
x1_line = []
y1_line = []
x2_line = []
y2_line = []
xpoints = len(x_axis)
intersection = []
while idx < xpoints:
    # Iterate over two line segments
    x = x_axis[idx]
    if id_px1>-1:
        if x >= points1[id_px1][0] and id_px1<len(points1)-1:
            y1_line = np.linspace(points1[id_px1][1], points1[id_px1+1][1], 1000) # 1.4 1.401 1.402 etc. bis 2.1
            x1_line = np.linspace(points1[id_px1][0], points1[id_px1+1][0], 1000)
            id_px1 = id_px1 + 1
            if id_px1 == len(points1):
                x1_line = []
                y1_line = []
                id_px1 = -1
    if id_px2>-1:
        if x >= points2[id_px2][0] and id_px2<len(points2)-1:
            y2_line = np.linspace(points2[id_px2][1], points2[id_px2+1][1], 1000)
            x2_line = np.linspace(points2[id_px2][0], points2[id_px2+1][0], 1000)
            id_px2 = id_px2 + 1
            if id_px2 == len(points2):
                x2_line = []
                y2_line = []
                id_px2 = -1
    if x1_line!=[] and y1_line!=[] and x2_line!=[] and y2_line!=[]:
        i = 0
        while abs(x-x1_line[i])>x_dist and i < len(x1_line)-1:
            i = i + 1
        y1_current = y1_line[i]
        j = 0
        while abs(x-x2_line[j])>x_dist and j < len(x2_line)-1:
            j = j + 1
        y2_current = y2_line[j]
        if abs(y2_current-y1_current)<y_dist and i != len(x1_line) and j != len(x2_line):
            ymax = max(y1_current, y2_current)
            ymin = min(y1_current, y2_current)
            xmax = max(x1_line[i], x2_line[j])
            xmin = min(x1_line[i], x2_line[j])
            intersection.append((x, ymin+(ymax-ymin)/2))
            ax.plot(x, y1_current, 'ro') # Plot the cross point
    idx += 1    
print "intersection points", intersection
plt.show()

解决方案 5:

点与点之间可能会发生交点。让我们探索下面的例子。

import numpy as np
import matplotlib.pyplot as plt
xs=np.arange(0, 20)
y1=np.arange(0, 20)*2
y2=np.array([1, 1.5, 3,  8,  9,  20, 23, 21, 13, 23, 18, 20, 23, 24, 31, 28, 30, 33, 37, 36])

绘制上面的两条曲线以及它们的交点,使用交点前后提出的平均坐标作为交点idx所有点都更接近第一条曲线

idx=np.argwhere(np.diff(np.sign(y1 - y2 )) != 0).reshape(-1) + 0
plt.plot(xs, y1)
plt.plot(xs, y2)
for i in range(len(idx)):
    plt.plot((xs[idx[i]]+xs[idx[i]+1])/2.,(y1[idx[i]]+y1[idx[i]+1])/2., 'ro')
plt.legend(['Y1', 'Y2'])
plt.show()   

在此处输入图片描述

使用交点之前和之后的平均坐标,但对于 y1 和 y2 曲线,通常更接近真实交点

plt.plot(xs, y1)
plt.plot(xs, y2)
for i in range(len(idx)):
    plt.plot((xs[idx[i]]+xs[idx[i]+1])/2.,(y1[idx[i]]+y1[idx[i]+1]+y2[idx[i]]+y2[idx[i]+1])/4., 'ro')
plt.legend(['Y1', 'Y2'])
plt.show()   

在此处输入图片描述

为了更加准确地估计交叉点,我们可以使用插值。

解决方案 6:

对于数组 f 和 g,我们可以简单地执行以下操作:

np.pad(np.diff(np.array(f > g).astype(int)), (1,0), 'constant', constant_values = (0,))

这将给出所有交叉点的数组。每个 1 表示从下向上的交叉,每个 -1 表示从上向下的交叉。

解决方案 7:

即使 f 和 g 相交,你也不能确定对于整数 i,f[i]== g[i](交点可能发生在点之间)。

你应该测试一下

# detect intersection by change in sign of difference
d = f - g
for i in range(len(d) - 1):
    if d[i] == 0. or d[i] * d[i + 1] < 0.:
        # crossover at i
        x_ = x[i]

解决方案 8:

我遇到了类似的问题,但有一个不连续函数,例如切线函数。为了避免在不连续处获取点(我不想考虑交点),我在之前使用 np.diff 和 np.sign 的解决方案上添加了一个容差参数。我将容差参数设置为两个数据点之间差异的平均值,这在我的情况下就足够了。

import numpy as np
import matplotlib.pyplot as plt

fig,ax = plt.subplots(nrows = 1,ncols = 2)

x = np.arange(0, 1000)
f = 2*np.arange(0, 1000)
g = np.tan(np.arange(0, 10, 0.01) * 2) * 1000


#here we set a threshold to decide if we will consider that point as a intersection
tolerance = np.abs(np.diff(f-g)).mean()
idx = np.argwhere((np.diff(np.sign(f - g)) != 0) & (np.abs(np.diff(f-g)) <= tolerance)).flatten()

#general case (tolerance = infinity)
tolerance = np.inf
idx2 = np.argwhere((np.diff(np.sign(f - g)) != 0) & (np.abs(np.diff(f-g)) <= tolerance)).flatten()

ax1,ax2 = ax

ax1.plot(x,f); ax1.plot(x,g)
ax2.plot(x,f); ax2.plot(x,g)

ax1.plot(x[idx], f[idx], 'o'); ax1.set_ylim(-3000,3000)
ax2.plot(x[idx2],f[idx2], 'o'); ax2.set_ylim(-3000,3000)
plt.show()

情节图片

解决方案 9:

作为一个有文档记录和测试过的函数(该算法归功于@Matt,在他的回答中,我只将示例改为更简单的例子,并使用linspace而不是arange来更好地处理非整数):

from typing import Iterable, Tuple
import numpy as np
import doctest

def intersect(x: np.array, f: np.array, g: np.array) -> Iterable[Tuple[(int, int)]]:
    """
    Finds the intersection points between `f` and `g` on the domain `x`.
    Given:
        - `x`: The discretized domain.
        - `f`: The discretized values of the first function calculated on the
               discretized domain.
        - `g`: The discretized values of the second function calculated on the
               discretized domain.
    Returns:
        An iterable containing the (x,y) points of intersection.


    Test case, line-parabola intersection:
        
    >>> x = np.linspace(0, 10, num=10000)
    >>> f = 3 * x
    >>> g = np.square(x)
    >>> list(intersect(x, f, g))
    [(0.0, 0.0), (2.999299929992999, 8.997899789978998)]
    """
    idx = np.argwhere(np.diff(np.sign(f - g))).flatten()
    return zip(x[idx], f[idx])

if __name__ == "__main__":
    doctest.testmod()

在 Python 2 中,只需删除类型提示。

解决方案 10:

可能有多个交叉点,你可以(x,y)通过以下列表推导找到每个交叉点处的点

intersections = [(x[i], f[i]) for i,_ in enumerate(zip(f,g)) if f[i] == g[i]]

举一个简单的例子

>>> x = [1,2,3,4,5]
>>> f = [2,4,6,8,10]
>>> g = [10,8,6,4,2]
>>> [(x[i], f[i]) for i,_ in enumerate(zip(f,g)) if f[i] == g[i]]
[(3, 6)]

因此,这在 处找到了一个交点x = 3, y = 6。请注意,如果您使用 ,则float两个值可能不完全相等,因此您可以使用一些公差而不是==

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用