Anotar barras con valores en los gráficos de barras de Pandas
Estaba buscando una manera de anotar mis barras en un diagrama de barras de Pandas con los valores numéricos redondeados de mi DataFrame.
>>> df=pd.DataFrame({'A':np.random.rand(2),'B':np.random.rand(2)},index=['value1','value2'] )
>>> df
A B
value1 0.440922 0.911800
value2 0.588242 0.797366
Me gustaría obtener algo como esto:
Intenté con este ejemplo de código, pero todas las anotaciones están centradas en las marcas x:
>>> ax = df.plot(kind='bar')
>>> for idx, label in enumerate(list(df.index)):
for acc in df.columns:
value = np.round(df.ix[idx][acc],decimals=2)
ax.annotate(value,
(idx, value),
xytext=(0, 15),
textcoords='offset points')
Lo obtienes directamente de los parches de los ejes:
for p in ax.patches:
ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))
Querrá modificar el formato de la cadena y los desplazamientos para centrar las cosas, tal vez usar el ancho desde p.get_width()
, pero eso debería ayudarlo a comenzar. Es posible que no funcione con gráficos de barras apiladas a menos que realice un seguimiento de las compensaciones en algún lugar.
A partir de matplotlib 3.4.0:
Axes.bar_label
Se ha agregado un nuevo método auxiliar para los gráficos de barras con etiquetado automático.
Para gráficos de barras de un solo grupo, proporcione ax.containers[0]
:
df = pd.DataFrame({'A': np.random.rand(2)}, index=['value1', 'value2'])
ax = df.plot.barh()
ax.bar_label(ax.containers[0])
Para gráficos de barras de varios grupos, itere ax.containers
:
df = pd.DataFrame({'A': np.random.rand(2), 'B': np.random.rand(2)}, index=['value1', 'value2'])
ax = df.plot.bar()
for container in ax.containers:
ax.bar_label(container)
Consulte las demostraciones de etiquetas de barras de matplotlib para obtener ejemplos completos utilizando los parámetros de estilo opcionales:
Axes.bar_label(self, container, labels=None, *, fmt='%g', label_type='edge', padding=0, **kwargs)
Solución que también maneja los valores negativos con formato flotante de muestra.
Todavía es necesario ajustar las compensaciones.
df=pd.DataFrame({'A':np.random.rand(2)-1,'B':np.random.rand(2)},index=['val1','val2'] )
ax = df.plot(kind='bar', color=['r','b'])
x_offset = -0.03
y_offset = 0.02
for p in ax.patches:
b = p.get_bbox()
val = "{:+.2f}".format(b.y1 + b.y0)
ax.annotate(val, ((b.x0 + b.x1)/2 + x_offset, b.y1 + y_offset))