2012-10-12 21 views
77

Sono piuttosto nuovo sia per python/matplotlib che per il suo utilizzo attraverso il notebook ipython. Sto cercando di aggiungere alcune linee di annotazione a un grafico esistente e non riesco a capire come rendere le linee su un grafico. Così, per esempio, se io tracciare la seguente:Aggiunta di una linea arbitraria a un grafico matplotlib nel notebook ipython

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

ottengo il seguente grafico:

beautiful scatter plot

Così come vorrei aggiungere una linea verticale da (70.100) fino a (70.250) ? Che dire di una linea diagonale da (70.100) a (90.200)?

Ho provato un paio di cose con Line2D() risultando in nient'altro che confusione da parte mia. In R userei semplicemente la funzione segment() che aggiungerebbe segmenti di linea. Esiste un equivalente in matplotlib?

risposta

131

È possibile tracciare direttamente le linee desiderate alimentando il comando plot con i dati corrispondenti (confini dei segmenti) :

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

(naturalmente si può scegliere il colore, spessore della linea, stile della linea, ecc)

Dal tuo esempio:

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

ottima risposta con illustrazioni eccellenti e complete! molte molte grazie! –

+2

Correzione minore, il codice sopra dovrebbe leggere 'x = np.arange (1, 101)'. –

+0

Questo non disegnerà una linea, ma solo un segmento. La domanda su come disegnare una linea per lanciare due punti dati rimane senza risposta. – Alexey

30

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

Le firme di chiamata di base sono:

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

questo è eccellente. Non avevo visto le funzioni 'vline()' o 'hline()'. Che dire delle linee diagonali? Ho modificato la domanda per aggiungere il bit diagonale ora che mi hai mostrato le linee h & v. –

+0

Prova a creare un 'DataFrame' contenente le coordinate x, y e tracciarle con' style = 'k-'' –

+0

Grazie, è molto utile – Alex

35

Non è troppo tardi per i nuovi arrivati.

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

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

Prende nell'intervallo y pure, utilizzando Ymin e Ymax.

+1

I parametri min/max di axhline e axvline sono valori scalari tra 0 e 1 che tracciano le linee in riferimento al fronte della trama. Sebbene sia un buon strumento, probabilmente non è la soluzione migliore alla dichiarazione del problema dell'autore di tracciare linee di annotazione. – binarysubstrate

+1

Questo è perfetto per voler aggiungere una linea di annotazione sullo sfondo che copre l'intero grafico. Se utilizzo la soluzione scelta sopra per disegnare una linea verticale a x = 1, devo specificare il minimo e il massimo y, e quindi il grafico si ridimensiona automaticamente con un buffer, quindi la linea non si estende su tutto il grafico, e questa è una seccatura. Questo è più elegante e non ridimensiona la trama. – Bonnie

1

Matplolib ora consente "linee di annotazione" come l'OP ricercato. La funzione annotate() consente diverse forme di percorsi di collegamento e una freccia senza testa e senza coda, cioè una linea semplice, è una di queste.

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

In the documentation si dice che si può solo disegnare una freccia con una stringa vuota come primo argomento.

Dall'esempio del PO:

%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

Proprio come nell'approccio in risposta gcalmettes, è possibile scegliere il colore, spessore della linea, stile della linea, ecc ..

Ecco una modifica di una parte del codice che renderebbe una delle due righe di esempio rossa, più ampia e non opaca al 100%.

# 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."), 
      ) 

È inoltre possibile aggiungere curva verso la linea che collega regolando la connectionstyle.

Problemi correlati