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 Метки нет (Все метки)
Здравствуйте, уважаемые форумчане.
Заранее спасибо.
0 |
Programming Эксперт 94731 / 64177 / 26122 Регистрация: 12.04.2006 Сообщений: 116,782 |
13.03.2020, 21:28 |
Ответы с готовыми решениями: Пересечение графиков Пересечение графиков Пересечение графиков Пересечение графиков 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 |
242 / 177 / 73 Регистрация: 17.10.2018 Сообщений: 749 |
|
15.03.2020, 08:40 |
4 |
Сообщение было отмечено Dart_pinokkio как решение РешениеПредположим, у Вас есть две функции, описывающие графики. Для простоты у1 = х**2 и у2 = х**3. Графики будут пересекаться при условии у1 = у2, т.е. х**2 = х**3. Ищем х и у для этого х.
1 |
4607 / 2028 / 359 Регистрация: 17.03.2012 Сообщений: 10,086 Записей в блоге: 6 |
|
16.03.2020, 19:06 |
5 |
Dart_pinokkio, во-первых, танцевать от графиков – глупо. Графики – это всего лишь линии, а искать надо решение уравнения f(x)=g(x).
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)
Ответ 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()
Сначала он вычисляет 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.
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()