matplotlib - example - Anote puntos de datos mientras traza desde Pandas DataFrame
plot() python (4)
Me gustaría anotar los puntos de datos con sus valores junto a los puntos en el gráfico. Los ejemplos que encontré solo tratan con x y y como vectores. Sin embargo, me gustaría hacer esto para un DataFrame de pandas que contiene varias columnas.
ax = plt.figure().add_subplot(1, 1, 1)
df.plot(ax = ax)
plt.show()
¿Cuál es la mejor manera de anotar todos los puntos para un DataFrame de varias columnas?
¿Desea utilizar una de las otras columnas como texto de la anotación? Esto es algo que hice recientemente.
Comenzando con algunos datos de ejemplo
In [1]: df
Out[1]:
x y val
0 -1.015235 0.840049 a
1 -0.427016 0.880745 b
2 0.744470 -0.401485 c
3 1.334952 -0.708141 d
4 0.127634 -1.335107 e
Trazar los puntos. Trazo y contra x, en este ejemplo.
In [2]: ax = df.set_index(''x'')[''y''].plot(style=''o'')
Escriba una función que haga un bucle sobre x, y, y el valor para anotar junto al punto.
In [3]: def label_point(x, y, val, ax):
a = pd.concat({''x'': x, ''y'': y, ''val'': val}, axis=1)
for i, point in a.iterrows():
ax.text(point[''x''], point[''y''], str(point[''val'']))
In [4]: label_point(df.x, df.y, df.val, ax)
In [5]: draw()
Aquí hay una versión (muy) ligeramente más pulida de la respuesta de Dan Allan :
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import string
df = pd.DataFrame({''x'':np.random.rand(10), ''y'':np.random.rand(10)},
index=list(string.ascii_lowercase[:10]))
Lo que da:
x y
a 0.541974 0.042185
b 0.036188 0.775425
c 0.950099 0.888305
d 0.739367 0.638368
e 0.739910 0.596037
f 0.974529 0.111819
g 0.640637 0.161805
h 0.554600 0.172221
i 0.718941 0.192932
j 0.447242 0.172469
Y entonces:
fig, ax = plt.subplots()
df.plot(''x'', ''y'', kind=''scatter'', ax=ax)
for k, v in df.iterrows():
ax.annotate(k, v)
Por último, si está en modo interactivo, es posible que necesite actualizar la trama:
fig.canvas.draw()
Lo que produce:
O, ya que parece increíblemente feo, puedes embellecer las cosas con bastante facilidad:
from matplotlib import cm
cmap = cm.get_cmap(''Spectral'')
df.plot(''x'', ''y'', kind=''scatter'', ax=ax, s=120, linewidth=0,
c=range(len(df)), colormap=cmap)
for k, v in df.iterrows():
ax.annotate(k, v,
xytext=(10,-5), textcoords=''offset points'',
family=''sans-serif'', fontsize=18, color=''darkslategrey'')
Que se ve mucho mejor
Encontré las respuestas anteriores bastante útiles, especialmente el ejemplo de LondonRob que mejoró un poco el diseño.
Lo único que me molestó es que no me gusta extraer datos de DataFrames para luego hacer un bucle sobre ellos. Parece un desperdicio del DataFrame.
Aquí había una alternativa que evita el bucle usando .apply (), e incluye las anotaciones más bonitas (pensé que la escala de colores era un poco exagerada y no podía hacer que la barra de colores desapareciera):
ax = df.plot(''x'', ''y'', kind=''scatter'', s=50 )
def annotate_df(row):
ax.annotate(row.name, row.values,
xytext=(10,-5),
textcoords=''offset points'',
size=18,
color=''darkslategrey'')
_ = df.apply(annotate_df, axis=1)
Editar notas
Edité mi ejemplo de código recientemente. Originalmente utilizaba lo mismo:
fig, ax = plt.subplots()
como las otras publicaciones para exponer los ejes, sin embargo esto no es necesario y hace que:
import matplotlib.pyplot as plt
La línea también es innecesaria.
También tenga en cuenta:
- Si está intentando reproducir este ejemplo y sus gráficos no tienen los puntos en el mismo lugar que cualquiera de los nuestros, puede ser porque el DataFrame estaba usando valores aleatorios. Probablemente hubiera sido menos confuso si hubiéramos usado una tabla de datos fija o una semilla aleatoria.
- Dependiendo de los puntos, es posible que tenga que jugar con los valores de
xytext
para obtener mejores ubicaciones.
Supongamos que su df
tiene varias columnas, y tres de las cuales son x
, y
y lbl
. Para anotar su gráfica de dispersión (x,y)
con lbl
, simplemente:
ax = df.plot(kind=''scatter'',x=''x'',y=''y'')
df[[''x'',''y'',''lbl'']].apply(lambda x: ax.text(*x),axis=1);