2015-02-27 16 views

Odpowiedz

33

Można użyć np.sign w połączeniu z np.diff i np.argwhere do uzyskania wskaźników punkty gdzie linie przecinają (w tym przypadku, punkty są [ 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)) != 0).reshape(-1) + 0 
plt.plot(x[idx], f[idx], 'ro') 
plt.show() 

plot of intersection points

Najpierw oblicza f - g i odpowiednie znaki za pomocą np.sign. Zastosowanie np.diff ujawnia wszystkie pozycje, w których zmienia się znak (np. Przecinają się linie). Korzystanie z np.argwhere podaje nam dokładne wskaźniki.

+0

Domyślam się, że powyższy kod podaje linię interpolującą punkty przecięcia. Rzeczywiście chcę wartości "x", a nie linii –

+2

'x [idx]' da ci odpowiednie wartości. – Matt

+0

ale x [idx] daje mi 10 wartości w powyższym kodzie? –

0

Może istnieć wiele skrzyżowań, można znaleźć punkt na każdym skrzyżowaniu (x,y) następującym listowego

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

Jako prosty przykład

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

Więc to znaleźć jeden punkt przecięcia na x = 3, y = 6 . Zauważ, że jeśli używasz float, dwie wartości mogą nie być dokładnie równe, więc możesz użyć pewnej tolerancji zamiast ==.

+0

punkt przecięcia nie ma w tablicy. Wykreślam obie krzywe, a następnie chciałbym narysować linię równoległą do osi Y przechodzącą przez punkt przecięcia i znaleźć wartość x –

1

Nawet jeśli f i g przecinają się, nie można mieć pewności, że f [i] == g [i] dla liczby całkowitej i (przecięcie prawdopodobnie występuje między punktami).

Należy zamiast testować jak

# 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] 
+0

Zapisuj to w trybie numpy-language, a skończysz z moją odpowiedzią;) – plonser

1

Dla tablic F i G, moglibyśmy po prostu wykonaj następujące czynności:

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

To daje tablicę wszystkich punktach rozjazdu. Co 1 to zwrot od dołu do góry i co -1 przejście od góry do dołu.

1

Cóż, szukałem matplotlib dla dwóch krzywych, które miały różny rozmiar i nie miały tych samych wartości x. Oto, co wymyślę:

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

Podobało mi się twoje podejście. Kciuki w górę –

0

Skrzyżowanie prawdopodobnie występuje między punktami. Przyjrzyjmy się przykładowi poniżej.

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

wykreślając krzywe 2 powyżej, wraz z ich skrzyżowań, z użyciem jako przecięcie średnie współrzędnych przed i po projektowany idx przecięcia wszystkie punkty znajdują się bliżej pierwszej krzywej.

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

enter image description here

stosując jako przecięcia średnich współrzędnych przed i po, ale na oba Y1 i Y2 krzywe zazwyczaj są bliżej prawdziwego skrzyżowaniu

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

enter image description here

dla jeszcze dokładniejsze oszacowanie przecięcia możemy wykorzystać interp olation.

Powiązane problemy