Anotar barras com valores em gráficos de barras Pandas

95

Eu estava procurando uma maneira de anotar minhas barras em um gráfico de barras do Pandas com os valores numéricos arredondados do meu 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

Eu gostaria de obter algo assim:

exemplo de anotação de gráfico de barra

Tentei com este exemplo de código, mas as anotações estão todas centradas nos x ticks:

>>> 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
fonte
Tom acertou em cheio, mas tenho uma solução mais complexa aqui: stackoverflow.com/questions/19917587/…
Paul H

Respostas:

155

Você obtém isso diretamente dos patches dos eixos:

for p in ax.patches:
    ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))

Você vai querer ajustar a formatação da string e os deslocamentos para centralizar as coisas, talvez usar a largura de p.get_width(), mas isso deve ajudá-lo a começar. Pode não funcionar com plotagens de barras empilhadas, a menos que você rastreie os deslocamentos em algum lugar.

TomAugspurger
fonte
29
Obrigado @TomAugsPurger, o seguinte funcionou: 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
Outra pergunta: como você lidaria com barras com valores negativos? Com o código acima, os rótulos estão sempre com coordenadas positivas, mesmo que o valor da barra seja negativo.
leroygr
1
Existe uma solução semelhante para barras horizontais: kind = barh?
Nickpick,
4
Descobri que isso funcionou 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
Obrigado @capitalistpug. Descobri que adicionar alinhamento horizontal tornou o seu ainda melhor. 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
32

Solução que também lida com os valores negativos com formatação flutuante de amostra.

Ainda precisa de ajustes de compensação.

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

valor rotulado gráfico de barra

tworec
fonte
0

O machado nos dá o tamanho da caixa.

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 mais clareza ::
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)
Bbox (x0 = 6,75, y0 = 756,0, x1 = 7,25, y1 = 2884,0)
Bbox (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 é a saída de patch.get_bbox () em meu programa.
podemos extrair os detalhes da caixa delimitadora daqui e manipular para nossos requisitos

congelamento de código
fonte