Как найти пересечение графиков python

For single solutions, this is answered in http://glowingpython.blogspot.de/2011/05/hot-to-find-intersection-of-two.html:

from scipy.optimize import fsolve

def findIntersection(fun1,fun2,x0):
    return fsolve(lambda x : fun1(x) - fun2(x),x0)

result = findIntersection(y,g,0.0)

Now, you just need to iterate through your range to get all the roots. This gives some duplicates, which you might be able to remove by using mpmath, setting the precision low enough, and using a set.

from scipy.optimize import fsolve
import numpy as np

rng = np.arange(-7.0, 7.0, 0.05)

def y(x):
    return np.sin(x)*(0.003*x**4 - 0.1*x**3 + x**2 + 4*x + 3)

def g(x):
    return -10 * np.arctan(x)

def findIntersection(fun1,fun2,x0):
    return fsolve(lambda x : fun1(x) - fun2(x),x0)

result = []
for x in rng:
    result.append(float(findIntersection(y,g,x)))

Well, I was looking for a matplotlib for two curves which were different in size and had not the same x values. Here is what I come up with:

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

#python #numpy #matplotlib #plot #visualization

Вопрос:

Я использую matplotlib для построения этих двух линейных графиков. Однако только иногда мои графики пересекались. Как я могу определить, пересекаются ли мои линейные графики?

 df = pd.read_csv("test.csv")

df2 = pd.read_csv("test2.csv")

x1 = df['A'].tolist()
x1 = np.array(x1)

y1 = df['D'].tolist()
y1 = np.array(y1)

x2 = df2['X'].tolist()
x2 = np.array(x2)

y2 = df2['Y'].tolist()
y2 = np.array(y2)

plt.plot(x1,y1)
plt.plot(x2,y2)
plt.show()
 

введите описание изображения здесь

Ответ №1:

Вы можете вычислить индекс точек пересечения с:

 idx = np.argwhere(np.diff(np.sign(y1 - y2))).flatten()
 

Если есть одно или несколько пересечений, idx отображается список точек пересечения, в противном случае это пустой список.

  • одно или несколько пересечений
     import numpy as np
    import matplotlib.pyplot as plt
    
    x1 = np.linspace(0, 10, 1000)
    x2 = np.linspace(-2, 5, 1000)
    y1 = np.sin(x1)
    y2 = np.cos(x2)   1
    
    idx = np.argwhere(np.diff(np.sign(y1 - y2))).flatten()
    
    fig, ax = plt.subplots()
    
    ax.plot(x1, y1, 'blue')
    ax.plot(x2, y2, 'red')
    
    plt.show()
     
     print(len(idx))
    2
     

    введите описание изображения здесь

  • никаких пересечений
     import numpy as np
    import matplotlib.pyplot as plt
    
    x1 = np.linspace(0, 10, 1000)
    x2 = np.linspace(-2, 5, 1000)
    y1 = np.sin(x1)
    y2 = np.cos(x2)   2
    
    idx = np.argwhere(np.diff(np.sign(y1 - y2))).flatten()
    
    fig, ax = plt.subplots()
    
    ax.plot(x1, y1, 'blue')
    ax.plot(x2, y2, 'red')
    
    plt.show()
     
     print(len(idx))
    0
     

    введите описание изображения здесь

Комментарии:

1. Я получаю эту ошибку : операнды не могут быть переданы вместе с фигурами (674,) (14,) . Я думаю, это из-за разных размеров numpy. Для построения первого графика потребовалось 674 балла, а для второго-всего 14 баллов. Знаете ли вы какие-либо способы преодолеть это?

Ответ №2:

Этот код выводит «пересечение», если значения y пересекаются в какой-то момент.

 mark = y1[0]-y2[0]

for i in range(len(y1)):
    if mark > 0:
        if y1[i]-y2[i] < 0:
        print('intersect')
    elif mark < 0:
        if y1[i]-y2[i] > 0:
            print('intersect')
 

Dart_pinokkio

2 / 2 / 0

Регистрация: 17.12.2018

Сообщений: 47

1

Пересечение графиков

13.03.2020, 21:28. Показов 13545. Ответов 5

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Здравствуйте, уважаемые форумчане.
Подскажите пожалуйста, как мне решить следующую задачку.
Есть у меня 2 графика функций.
У них есть точки пересечения. Как координаты этих точек вывести в переменные?
Вот код:

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import sys
from PyQt5.QtWidgets import QApplication
import pyqtgraph as pg
import numpy as np
 
F0=200
 
app = QApplication(sys.argv)
a = np.linspace(1, F0 * 2, 2000)
 
plt = pg.plot()
plt.setWindowTitle('pyqtgraph example: Legend')
plt.addLegend()
 
c1 = plt.plot(500*a, a+100, pen='r', name='red plot')
c2 = plt.plot(a**2, a, pen='g', name='green plot')
 
status = app.exec_()
sys.exit(status)

Заранее спасибо.



0



Programming

Эксперт

94731 / 64177 / 26122

Регистрация: 12.04.2006

Сообщений: 116,782

13.03.2020, 21:28

Ответы с готовыми решениями:

Пересечение графиков
Требуется построить график параболы и гиперболы с заданными коэффициентами, и найти точки их…

Пересечение графиков
Задача. Дана окружность, заданная уравнением: x^2+y^2=1, и дана прямая. Прямая задаётся по двум…

Пересечение графиков
Есть два графика, которые были построены с помощью функции lsline, можно ли найти точку пересечения…

Пересечение графиков
Нужно найти пересечение двух или более графиков (любых) и подписать точку их пересечения

5

3919 / 2475 / 524

Регистрация: 07.11.2019

Сообщений: 4,117

13.03.2020, 22:24

2

Решить квадратное уравнение.



1



2 / 2 / 0

Регистрация: 17.12.2018

Сообщений: 47

14.03.2020, 19:55

 [ТС]

3

Добрый вечер, а можно как нибудь дать более развернутый ответ?
Я дал частный (простой) случай задачи. На самом деле мне необходимо решить подобную задачу, но с другими графиками. Насколько я помню математику, то точки пересечения графиков – это значения, при которых их разность равна 0. А таких точек может быть и 0 и 1 и 10. Вот мне и необходим алгоритм получения переменных, содержащих эти точки. Если можно, покажите пожалуйста пример решения этого вопроса. Я подозреваю, что в numpy есть возможности, чтоб не изобретать велосипед. Но с программированием я слабо знаком.



0



242 / 177 / 73

Регистрация: 17.10.2018

Сообщений: 749

15.03.2020, 08:40

4

Лучший ответ Сообщение было отмечено Dart_pinokkio как решение

Решение

Предположим, у Вас есть две функции, описывающие графики. Для простоты у1 = х**2 и у2 = х**3. Графики будут пересекаться при условии у1 = у2, т.е. х**2 = х**3. Ищем х и у для этого х.



1



Эксперт Python

4607 / 2028 / 359

Регистрация: 17.03.2012

Сообщений: 10,086

Записей в блоге: 6

16.03.2020, 19:06

5

Dart_pinokkio, во-первых, танцевать от графиков – глупо. Графики – это всего лишь линии, а искать надо решение уравнения f(x)=g(x).
А там уже возможны варианты, в зависимости от сложности и допустимого разнообразия функций.
Если найти пересечение прямой с параболой – то таки да, задача сводится к квадратному уравнению, задача для 6-го класса (или когда там их изучают).



2



2 / 2 / 0

Регистрация: 17.12.2018

Сообщений: 47

16.03.2020, 22:43

 [ТС]

6

Всем спасибо, задачу решил. Просто там очень сложные функции пришлось приравнивать. В 4, 3, 2 степени были переменные. Постоянно ошибался. Пришлось в Mathcad формулу выводить. Всем спасибо за помощь, кто откликнулся.



0



Пусть 0 <= x <= 1. У меня два столбца f и g длины 5000 соответственно. Теперь я рисую:

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

Я хочу найти точку “x”, где пересекает кривая. Я не хочу найти пересечение f и g.
Я могу сделать это просто:

   set(f) & set(g)

4b9b3361

Ответ 1

Вы можете использовать np.sign в сочетании с np.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()

plot of intersection points

Сначала он вычисляет f - g и соответствующие знаки, используя np.sign. Применение np.diff показывает все позиции, где знак изменяется (например, пересекаются линии). Используя np.argwhere дает нам точные индексы.

Ответ 2

Ну, я искал 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()

Ответ 3

Для массивов f и g мы могли бы просто сделать следующее:

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

Это даст массив всех точек кроссовера. Каждый 1 является кроссовером снизу вверх и каждым -1 кроссовером сверху вниз.

Ответ 4

Там может быть несколько пересечений, вы можете найти точку (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, два значения могут быть не равными, поэтому вы можете использовать некоторый допуск вместо ==.

Ответ 5

Даже если f и g пересекаются, вы не можете быть уверены, что 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]

Ответ 6

Пересечение, вероятно, происходит между точками. Давайте рассмотрим пример ниже.

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

построив 2 кривые выше вместе с их пересечениями, используя в качестве пересечения средние координаты до и после предложенного из пересечения 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()   

введите описание изображения здесь

Для еще более точной оценки пересечения мы могли бы использовать интерполяцию.

Ответ 7

Здесь есть решение, которое:

  • Работает с N-мерными данными
  • Использует евклидовое расстояние, а не просто нахождение перекрестков по оси y
  • Является более эффективным с большим количеством данных (он запрашивает KD-дерево, которое должно запрашивать в логарифмическом времени вместо линейного времени).
  • Вы можете изменить distance_upper_bound в запросе KD-дерева, чтобы определить, насколько близко достаточно близко.
  • При необходимости вы можете запросить KD-дерево со многими точками одновременно. Примечание. Если вам нужно запросить тысячи точек сразу, вы можете получить значительное увеличение производительности, запросив KD-дерево с другим деревом KD.

enter image description here

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

Добавить комментарий