Anotar barras con valores en diagramas de barras de Pandas

89

Estaba buscando una forma de anotar mis barras en un gráfico 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:

ejemplo de anotación de gráfico de barras

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')
leroygr
fuente
Tom lo logró, pero tengo una solución más compleja aquí: stackoverflow.com/questions/19917587/…
Paul H

Respuestas:

148

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á ajustar el formato de cadena y las compensaciones para centrar las cosas, tal vez use el ancho de 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 alguna parte.

TomAugspurger
fuente
28
Gracias @TomAugsPurger, lo siguiente funcionó: for p in ax.patches: ax.annotate(np.round(p.get_height(),decimals=2), (p.get_x()+p.get_width()/2., p.get_height()), ha='center', va='center', xytext=(0, 10), textcoords='offset points')
leroygr
2
Otra pregunta: ¿cómo manejarías las barras con valores negativos? Con el código anterior, las etiquetas siempre tienen coordenadas positivas, incluso si el valor de la barra es negativo.
leroygr
1
¿Existe una solución similar para las barras horizontales: kind = barh?
Nickpick
4
Encontré que esto funciona para barh:ax.annotate(str(p.get_width()), (p.get_x() + p.get_width(), p.get_y()), xytext=(5, 10), textcoords='offset points')
Kamil Sindi
2
Gracias @capitalistpug. Descubrí que agregar alineación horizontal mejoraba aún más el tuyo. ax.annotate(str(int(p.get_width())), (p.get_x() + p.get_width(), p.get_y()), xytext=(-2, 4), textcoords='offset points', horizontalalignment='right') +1
DaveL17
31

Solución que también maneja los valores negativos con formato flotante de muestra.

Todavía necesita 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))

gráfico de barras con etiqueta de valor

tworec
fuente
0

El hacha nos da el tamaño de la caja.

x_position=##define a value
y_position=##define a value
for patch in ax.patches:
    b= patch.get_bbox()
    y_value=b.y1-b.y0
    ax.annotate(y_value, "x_position" , "y_position"))
plt.show()

para mayor claridad ::
Bbox (x0 = 3.75, y0 = 0.0, x1 = 4.25, y1 = 868.0)
Bbox (x0 = 4.75, y0 = 0.0, x1 = 5.25, y1 = 868.0)
Bbox (x0 = 5.75, y0 = 0.0 , x1 = 6.25, y1 = 1092.0)
Bbox (x0 = 6.75, y0 = 0.0, x1 = 7.25, y1 = 756.0)
Bbox (x0 = 7.75, y0 = 0.0, x1 = 8.25, y1 = 756.0)
Bbox (x0 = 8.75 , y0 = 0.0, x1 = 9.25, y1 = 588.0)
Bbox (x0 = 3.75, y0 = 868.0, x1 = 4.25, y1 = 3724.0)
Bbox (x0 = 4.75, y0 = 868.0, x1 = 5.25, y1 = 3528.0)
Bbox (x0 = 5.75, y0 = 1092.0, x1 = 6.25, y1 = 3948.0) Caja B
(x0 = 6.75, y0 = 756.0, x1 = 7.25, y1 = 2884.0) Caja B
(x0 = 7.75, y0 = 756.0, x1 = 8.25, y1 = 3024.0)
Bbox (x0 = 0.75, y0 = 4004.0, x1 = 1.25, y1 = 4396.0)
Bbox (x0 = 1.75, y0 = 3668.0, x1 = 2.25, y1 = 4060.0)
Bbox (x0 = 2.75, y0 = 3864.0, x1 = 3,25, y1 = 4060,0)

esta es la salida de patch.get_bbox () en mi programa.
podemos extraer los detalles del cuadro delimitador desde aquí y manipularlos según nuestro requisito

congelación de código
fuente