Diagrama de dispersión de Matplotlib con texto diferente en cada punto de datos

252

Estoy tratando de hacer un diagrama de dispersión y anotar puntos de datos con diferentes números de una lista. Entonces, por ejemplo, quiero trazar yvs xy anotar con los números correspondientes de n.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]
ax = fig.add_subplot(111)
ax1.scatter(z, y, fmt='o')

¿Algunas ideas?

Labibah
fuente
También puede obtener un diagrama de dispersión con etiquetas de información sobre herramientas al pasar el mouse utilizando la biblioteca mpld3. mpld3.github.io/examples/scatter_tooltip.html
Claude COULOMBE

Respuestas:

466

No conozco ningún método de trazado que tome matrices o listas, pero podría usarlo annotate()mientras itera sobre los valores n.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

Hay muchas opciones de formato para annotate(), consulte el sitio web matplotlib:

ingrese la descripción de la imagen aquí

Rutger Kassies
fuente
1
Funciona bien sobre Seaborn regplots sin demasiada interrupción, también.
ijoseph
@Rutger Utilizo un marco de datos de pandas y de alguna manera obtengo un KeyError- ¿así que supongo dict()que se espera un objeto? ¿Hay alguna otra manera de etiquetar los datos utilizando enumerate, annotatey una trama de datos pandas?
Rachel
@ Rachel, puede usar for row in df.iterrows():y luego acceder a los valores con row['text'], row['x-coord']etc. Si publica una pregunta por separado, la echaré un vistazo.
Rutger Kassies
@RutgerKassies Gracias, Rutger! Publiqué una pregunta aquí stackoverflow.com/questions/41481153/… Me temo que puede ser muy similar a esta misma pregunta. Pero no puedo resolverlo de alguna manera. ¡Gracias por tu ayuda!
Rachel
1
@aviator, desafortunadamente no incorporado. Pero vea, por ejemplo, esto usando el motor de diseño de networkx: stackoverflow.com/a/34697108/1755432
Rutger Kassies
32

En versiones anteriores a matplotlib 2.0, ax.scatterno es necesario trazar texto sin marcadores. En la versión 2.0, ax.scatterdeberá establecer el rango y los marcadores adecuados para el texto.

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

Y en este enlace puedes encontrar un ejemplo en 3d.

rafaelvalle
fuente
¡Esto es asombroso! Gracias por compartir esta solución. ¿También puede compartir cuál es el código adecuado para establecer el tamaño de la figura? Implementaciones como las que plt.figure(figsize=(20,10))no funcionan como se esperaba, en el sentido de que invocar este código en realidad no cambia el tamaño de la imagen. Esperamos su ayuda. ¡Gracias!
Levine
fig, ax = plt.subplots (figsize = (20,10))
rafaelvalle
21

En caso de que alguien esté tratando de aplicar las soluciones anteriores a .scatter () en lugar de a .subplot (),

Traté de ejecutar el siguiente código

y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.scatter(z, y)

for i, txt in enumerate(n):
    ax.annotate(txt, (z[i], y[i]))

Pero se encontraron con errores que indican "no se puede desempaquetar el objeto PathCollection no iterable", con el error apuntando específicamente a la línea de código fig, ax = plt.scatter (z, y)

Finalmente resolví el error usando el siguiente código

plt.scatter(z, y)

for i, txt in enumerate(n):
    plt.annotate(txt, (z[i], y[i]))

No esperaba que hubiera una diferencia entre .scatter () y .subplot () debería haberlo sabido mejor.

Heather Claxton
fuente
11

También puede usar pyplot.text(ver aquí ).

def plot_embeddings(M_reduced, word2Ind, words):
""" Plot in a scatterplot the embeddings of the words specified in the list "words".
    Include a label next to each point.
"""
for word in words:
    x, y = M_reduced[word2Ind[word]]
    plt.scatter(x, y, marker='x', color='red')
    plt.text(x+.03, y+.03, word, fontsize=9)
plt.show()

M_reduced_plot_test = np.array([[1, 1], [-1, -1], [1, -1], [-1, 1], [0, 0]])
word2Ind_plot_test = {'test1': 0, 'test2': 1, 'test3': 2, 'test4': 3, 'test5': 4}
words = ['test1', 'test2', 'test3', 'test4', 'test5']
plot_embeddings(M_reduced_plot_test, word2Ind_plot_test, words)

ingrese la descripción de la imagen aquí

irudyak
fuente
7

Python 3.6+:

coordinates = [('a',1,2), ('b',3,4), ('c',5,6)]
for x in coordinates: plt.annotate(x[0], (x[1], x[2]))
palash
fuente
2

Como una línea usando la comprensión de la lista y numpy:

[ax.annotate(x[0], (x[1], x[2])) for x in np.array([n,z,y]).T]

La configuración es lo mismo que la respuesta de Rutger.

andor kesselman
fuente
1

Me encantaría agregar que incluso puedes usar flechas / cuadros de texto para anotar las etiquetas. Esto es lo que quiero decir:

import random
import matplotlib.pyplot as plt


y = [2.56422, 3.77284, 3.52623, 3.51468, 3.02199]
z = [0.15, 0.3, 0.45, 0.6, 0.75]
n = [58, 651, 393, 203, 123]

fig, ax = plt.subplots()
ax.scatter(z, y)

ax.annotate(n[0], (z[0], y[0]), xytext=(z[0]+0.05, y[0]+0.3), 
    arrowprops=dict(facecolor='red', shrink=0.05))

ax.annotate(n[1], (z[1], y[1]), xytext=(z[1]-0.05, y[1]-0.3), 
    arrowprops = dict(  arrowstyle="->",
                        connectionstyle="angle3,angleA=0,angleB=-90"))

ax.annotate(n[2], (z[2], y[2]), xytext=(z[2]-0.05, y[2]-0.3), 
    arrowprops = dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1))

ax.annotate(n[3], (z[3], y[3]), xytext=(z[3]+0.05, y[3]-0.2), 
    arrowprops = dict(arrowstyle="fancy"))

ax.annotate(n[4], (z[4], y[4]), xytext=(z[4]-0.1, y[4]-0.2),
    bbox=dict(boxstyle="round", alpha=0.1), 
    arrowprops = dict(arrowstyle="simple"))

plt.show()

Lo que generará el siguiente gráfico: ingrese la descripción de la imagen aquí

Anwarvic
fuente