2012-10-12 16 views
77

Jestem raczej nowy zarówno dla Pythona/Matplotlib, jak i korzystania z niego przez notatnik ipython. Próbuję dodać kilka linii adnotacji do istniejącego wykresu i nie mogę wymyślić, jak renderować linie na wykresie. Tak więc, na przykład, jeśli wykreślić następujące:Dodawanie arbitralnej linii do wykresu matplotlib w ipythonie notebooka

import numpy as np 
np.random.seed(5) 
x = arange(1, 101) 
y = 20 + 3 * x + np.random.normal(0, 60, 100) 
p = plot(x, y, "o") 

otrzymuję następujący wykres:

beautiful scatter plot

tak jak bym dodać pionową linię z (70,100) do (70250) ? A co z linią ukośną od (70,100) do (90,200)?

Próbowałem już kilku rzeczy z Line2D(), powodując tylko pomyłkę z mojej strony. W R po prostu użyłbym funkcji segments(), która dodawałaby segmenty linii. Czy istnieje odpowiednik w matplotlib?

Odpowiedz

131

Można bezpośrednio wykreślić linie chcesz karmiąc polecenia plot z odpowiednimi danymi (granice segmentów) :

plot([x1, x2], [y1, y2], color='k', linestyle='-', linewidth=2)

(oczywiście można wybrać kolor, szerokość linii, styl linii, itd.)

ze swojego przykład:

import numpy as np 
import matplotlib.pyplot as plt 

np.random.seed(5) 
x = np.arange(1, 101) 
y = 20 + 3 * x + np.random.normal(0, 60, 100) 
plt.plot(x, y, "o") 


# draw vertical line from (70,100) to (70, 250) 
plt.plot([70, 70], [100, 250], 'k-', lw=2) 

# draw diagonal line from (70, 90) to (90, 200) 
plt.plot([70, 90], [90, 200], 'k-') 

plt.show() 

new chart

+0

wspaniała odpowiedź z doskonałymi i pełnymi ilustracjami! wielkie dzięki! –

+2

Drobna korekcja, powyższy kod powinien brzmieć "x = np.arange (1, 101)". –

+0

Nie spowoduje to narysowania linii, a jedynie segmentu. Pytanie, jak narysować linię, rzucić dwa dane punkty, pozostaje bez odpowiedzi. – Alexey

30

Korzystanie vlines:

import numpy as np 
np.random.seed(5) 
x = arange(1, 101) 
y = 20 + 3 * x + np.random.normal(0, 60, 100) 
p = plot(x, y, "o") 
vlines(70,100,250) 

The podstawowych podpisów zaproszeniem:

vlines(x, ymin, ymax) 
hlines(y, xmin, xmax) 
+2

To jest doskonałe. Nie widziałem funkcji 'vline()' lub 'hline()'. A co z liniami ukośnymi? Zmieniłem to pytanie, by dodać przekątną teraz, gdy pokazałeś mi linie h i v. –

+0

Spróbuj utworzyć 'DataFrame' zawierającą współrzędne x, y i narysując je za pomocą' style = 'k-'' –

+0

Dziękuję, to bardzo przydatna – Alex

35

Jeszcze nie jest za późno na przybyszów.

plt.axvline(x, color='r') 

http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.axvline

zajmuje zakres Y, jak również za pomocą Ymin i ymax.

+1

Parametry min/max axhline i axvline są wartościami skalarnymi między 0 a 1, które kreślą linie w odniesieniu do krawędzi wykresu. Chociaż jest to dobre narzędzie, prawdopodobnie nie jest najlepszym rozwiązaniem autorskiego opisu problemu rysowania linii opisu. – binarysubstrate

+1

Jest to idealne rozwiązanie, jeśli chcesz dodać linię adnotacji w tle obejmującą cały wykres. Jeśli użyję wybranego rozwiązania powyżej, aby narysować pionową linię przy x = 1, muszę określić min i maks y, a następnie wykres automatycznie zmieni się wraz z buforem, aby linia nie rozciągała się na całej powierzchni, oraz to jest kłopot. Jest to bardziej eleganckie i nie zmienia rozmiaru fabuły. – Bonnie

1

Matplolib pozwala teraz na "linie adnotacji", których szukał OP. Funkcja annotate() umożliwia kilka postaci ścieżek łączenia, a jednym z nich jest strzałka bez głowy i bez końca, tj. Prosta linia.

ax.annotate("", 
      xy=(0.2, 0.2), xycoords='data', 
      xytext=(0.8, 0.8), textcoords='data', 
      arrowprops=dict(arrowstyle="-", 
         connectionstyle="arc3, rad=0"), 
      ) 

W the documentation mówi można wyciągnąć tylko strzałę z pustym ciągiem jako pierwszy argument.

Od przykład OP:

%matplotlib notebook 
import numpy as np 
import matplotlib.pyplot as plt 

np.random.seed(5) 
x = np.arange(1, 101) 
y = 20 + 3 * x + np.random.normal(0, 60, 100) 
plt.plot(x, y, "o") 


# draw vertical line from (70,100) to (70, 250) 
plt.annotate("", 
       xy=(70, 100), xycoords='data', 
       xytext=(70, 250), textcoords='data', 
       arrowprops=dict(arrowstyle="-", 
           connectionstyle="arc3,rad=0."), 
      ) 

# draw diagonal line from (70, 90) to (90, 200) 
plt.annotate("", 
       xy=(70, 90), xycoords='data', 
       xytext=(90, 200), textcoords='data', 
       arrowprops=dict(arrowstyle="-", 
           connectionstyle="arc3,rad=0."), 
      ) 

plt.show() 

Example inline image

Podobnie jak w podejściu w odpowiedzi gcalmettes, można wybrać kolor, grubość linii, styl linii, itp ..

Oto zmiana części kodu, która spowodowałaby, że jedna z dwóch przykładowych linii jest czerwona, szersza, a nie w 100% nieprzejrzysta.

# draw vertical line from (70,100) to (70, 250) 
plt.annotate("", 
       xy=(70, 100), xycoords='data', 
       xytext=(70, 250), textcoords='data', 
       arrowprops=dict(arrowstyle="-", 
           edgecolor = "red", 
           linewidth=5, 
           alpha=0.65, 
           connectionstyle="arc3,rad=0."), 
      ) 

Można również dodać krzywą linią łączącą regulując connectionstyle.

Powiązane problemy