2012-10-12 253 views
77

Soy bastante nuevo para python/matplotlib y lo uso a través del cuaderno ipython. Estoy intentando agregar algunas líneas de anotación a un gráfico existente y no puedo entender cómo representar las líneas en un gráfico. Así, por ejemplo, si yo trazo la siguiente:Agregar una línea arbitraria a un diagrama de matplotlib en el cuaderno 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") 

me sale el siguiente gráfico:

beautiful scatter plot

Entonces, ¿cómo iba a añadir una línea vertical desde (70.100) hasta (70.250) ? ¿Qué pasa con una línea diagonal de (70,100) a (90,200)?

He intentado algunas cosas con Line2D() resultando en nada más que la confusión de mi parte. En R simplemente usaría la función de segmentos() que agregaría segmentos de línea. ¿Hay un equivalente en matplotlib?

Respuesta

131

Puede representar directamente las líneas que desea alimentando el comando plot con los datos correspondientes (límites de los segmentos) :

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

(por supuesto, usted puede elegir el color, grosor de línea, estilo de línea, etc.)

de su ejemplo:

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

¡excelente respuesta con ilustraciones excelentes y completas! ¡muchas muchas gracias! –

+2

Corrección secundaria, el código anterior debe leer 'x = np.arange (1, 101)'. –

+0

Esto no dibujará una línea, sino solo un segmento. La pregunta de cómo dibujar una línea arrojar dos puntos determinados sigue sin respuesta. – Alexey

30

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

Las firmas de llamadas básicas son:

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

eso es excelente. No había visto las funciones 'vline()' o 'hline()'. ¿Qué hay de las líneas diagonales? Edité la pregunta para agregar el bit diagonal ahora que me has mostrado las líneas h & v. –

+0

Intenta hacer un 'DataFrame' que contenga las coordenadas x, y y dibujarlas con' style = 'k-'' –

+0

Gracias, es muy útil – Alex

35

No es demasiado tarde para los recién llegados.

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

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

Toma el rango de y, así, utilizando ymin y ymax.

+1

Los parámetros min/max de axhline y axvline son valores escalares entre 0 y 1 que trazan líneas en referencia al borde de la trama. Aunque es una buena herramienta, probablemente no sea la mejor solución al enunciado del problema del autor sobre las líneas de anotación del dibujo. – binarysubstrate

+1

Esto es perfecto para querer agregar una línea de anotación en segundo plano que abarque todo el gráfico. Si utilizo la solución elegida arriba para dibujar una línea vertical en x = 1, tengo que especificar el mínimo y el máximo y, y luego el diagrama cambia el tamaño automáticamente con un buffer, por lo que la línea no se extiende por toda la gráfica, y eso es una molestia. Esto es más elegante y no cambia el tamaño de la trama. – Bonnie

1

Matplolib ahora permite 'líneas de anotación' como el OP estaba buscando. La función annotate() permite varias formas de rutas de conexión y una flecha sin cabeza y sin cola, es decir, una línea simple, es una de ellas.

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

En the documentation dice que se puede dibujar solamente una flecha con una cadena vacía como el primer argumento.

del ejemplo de la 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

Al igual que en el enfoque en la respuesta de gcalmettes, se puede elegir el color, grosor de línea, estilo de línea, etc ..

Aquí hay una alteración de una parte del código que haría que una de las dos líneas de ejemplo fuera roja, más ancha y no 100% opaca.

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

También puede agregar curva a la línea que conecta mediante el ajuste de la connectionstyle.

Cuestiones relacionadas