¿Cómo mostrar el valor de la barra en cada barra con pyplot.barh ()?

105

Genere un diagrama de barras, ¿cómo puedo mostrar el valor de la barra en cada barra?

Trama actual:

ingrese la descripción de la imagen aquí

Lo que estoy tratando de conseguir:

ingrese la descripción de la imagen aquí

Mi código:

import os
import numpy as np
import matplotlib.pyplot as plt

x = [u'INFO', u'CUISINE', u'TYPE_OF_PLACE', u'DRINK', u'PLACE', u'MEAL_TIME', u'DISH', u'NEIGHBOURHOOD']
y = [160, 167, 137, 18, 120, 36, 155, 130]

fig, ax = plt.subplots()    
width = 0.75 # the width of the bars 
ind = np.arange(len(y))  # the x locations for the groups
ax.barh(ind, y, width, color="blue")
ax.set_yticks(ind+width/2)
ax.set_yticklabels(x, minor=False)
plt.title('title')
plt.xlabel('x')
plt.ylabel('y')      
#plt.show()
plt.savefig(os.path.join('test.png'), dpi=300, format='png', bbox_inches='tight') # use format='svg' or 'pdf' for vectorial pictures
Franck Dernoncourt
fuente

Respuestas:

172

Añadir:

for i, v in enumerate(y):
    ax.text(v + 3, i + .25, str(v), color='blue', fontweight='bold')

resultado:

ingrese la descripción de la imagen aquí

Los valores y vson tanto la ubicación x como los valores de cadena para ax.text, y convenientemente el diagrama de barras tiene una métrica de 1 para cada barra, por lo que la enumeración ies la ubicación y.

cphlewis
fuente
11
tal vez reemplace use va = 'center', en lugar de "i + .25" para la alineación horizontal
mathause
11
plt.text(v, i, " "+str(v), color='blue', va='center', fontweight='bold')
João Cartucho
¿Cómo puedo suprimir la salida de texto en un cuaderno jupyter? ";" al final no funciona.
Ralf Hundewadt
Si quiero imprimir NEIGHBORHOOD en la parte superior de la barra y lo mismo para todas las barras baove, en lugar de a la izquierda, lo que se debe hacer. Probé y busqué en muchos lugares, pero no tengo ni idea hasta ahora.
Rishi Bansal
@RalfHundewadt acaba de poner una plt.show()cláusula al final. Por ejemplo: df.plot(); plt.show()
Jairo Alves
36

He notado que el código de ejemplo de API contiene un ejemplo de gráfico de barras con el valor de la barra que se muestra en cada barra:

"""
========
Barchart
========

A bar plot with errorbars and height labels on individual bars
"""
import numpy as np
import matplotlib.pyplot as plt

N = 5
men_means = (20, 35, 30, 35, 27)
men_std = (2, 3, 4, 1, 2)

ind = np.arange(N)  # the x locations for the groups
width = 0.35       # the width of the bars

fig, ax = plt.subplots()
rects1 = ax.bar(ind, men_means, width, color='r', yerr=men_std)

women_means = (25, 32, 34, 20, 25)
women_std = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind + width, women_means, width, color='y', yerr=women_std)

# add some text for labels, title and axes ticks
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5'))

ax.legend((rects1[0], rects2[0]), ('Men', 'Women'))


def autolabel(rects):
    """
    Attach a text label above each bar displaying its height
    """
    for rect in rects:
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2., 1.05*height,
                '%d' % int(height),
                ha='center', va='bottom')

autolabel(rects1)
autolabel(rects2)

plt.show()

salida:

ingrese la descripción de la imagen aquí

FYI ¿Cuál es la unidad de la variable de altura en "barh" de matplotlib? (a partir de ahora, no hay una manera fácil de establecer una altura fija para cada barra)

Franck Dernoncourt
fuente
1
Parece que get_x () redondea el número hacia arriba incluso si la x original tiene decimales. ¿Cómo se pueden mostrar más lugares decimales?
ru111
1
tarde a la fiesta, pero para cualquier otra persona que use esta altura + 0.1 en lugar de 1.05 * la altura en la función de etiqueta automática crea un espacio constante entre la barra y el texto
jnPy
19

Para cualquiera que desee tener su etiqueta en la base de sus barras, simplemente divida v por el valor de la etiqueta de esta manera:

for i, v in enumerate(labels):
    axes.text(i-.25, 
              v/labels[i]+100, 
              labels[i], 
              fontsize=18, 
              color=label_color_list[i])

(nota: agregué 100 por lo que no estaba absolutamente en la parte inferior)

Para obtener un resultado como este: ingrese la descripción de la imagen aquí

Skromak
fuente
¿Seguramente v == labels[i]y entonces la tercera y cuarta línea podrían ser simplemente 101, v?
It'sNotALie.
14

Sé que es un hilo antiguo, pero aterricé aquí varias veces a través de Google y creo que ninguna respuesta dada es realmente satisfactoria todavía. Intente utilizar una de las siguientes funciones:

EDITAR : Como estoy obteniendo algunos Me gusta en este antiguo hilo, también quiero compartir una solución actualizada (básicamente uniendo mis dos funciones anteriores y decidiendo automáticamente si es un gráfico de barras o hbar):

def label_bars(ax, bars, text_format, **kwargs):
    """
    Attaches a label on every bar of a regular or horizontal bar chart
    """
    ys = [bar.get_y() for bar in bars]
    y_is_constant = all(y == ys[0] for y in ys)  # -> regular bar chart, since all all bars start on the same y level (0)

    if y_is_constant:
        _label_bar(ax, bars, text_format, **kwargs)
    else:
        _label_barh(ax, bars, text_format, **kwargs)


def _label_bar(ax, bars, text_format, **kwargs):
    """
    Attach a text label to each bar displaying its y value
    """
    max_y_value = ax.get_ylim()[1]
    inside_distance = max_y_value * 0.05
    outside_distance = max_y_value * 0.01

    for bar in bars:
        text = text_format.format(bar.get_height())
        text_x = bar.get_x() + bar.get_width() / 2

        is_inside = bar.get_height() >= max_y_value * 0.15
        if is_inside:
            color = "white"
            text_y = bar.get_height() - inside_distance
        else:
            color = "black"
            text_y = bar.get_height() + outside_distance

        ax.text(text_x, text_y, text, ha='center', va='bottom', color=color, **kwargs)


def _label_barh(ax, bars, text_format, **kwargs):
    """
    Attach a text label to each bar displaying its y value
    Note: label always outside. otherwise it's too hard to control as numbers can be very long
    """
    max_x_value = ax.get_xlim()[1]
    distance = max_x_value * 0.0025

    for bar in bars:
        text = text_format.format(bar.get_width())

        text_x = bar.get_width() + distance
        text_y = bar.get_y() + bar.get_height() / 2

        ax.text(text_x, text_y, text, va='center', **kwargs)

Ahora puede usarlos para gráficos de barras normales:

fig, ax = plt.subplots((5, 5))
bars = ax.bar(x_pos, values, width=0.5, align="center")
value_format = "{:.1%}"  # displaying values as percentage with one fractional digit
label_bars(ax, bars, value_format)

o para gráficos de barras horizontales:

fig, ax = plt.subplots((5, 5))
horizontal_bars = ax.barh(y_pos, values, width=0.5, align="center")
value_format = "{:.1%}"  # displaying values as percentage with one fractional digit
label_bars(ax, horizontal_bars, value_format)
SaturnoDeTitan
fuente
14

Utilice plt.text () para poner texto en el gráfico.

Ejemplo:

import matplotlib.pyplot as plt
N = 5
menMeans = (20, 35, 30, 35, 27)
ind = np.arange(N)

#Creating a figure with some fig size
fig, ax = plt.subplots(figsize = (10,5))
ax.bar(ind,menMeans,width=0.4)
#Now the trick is here.
#plt.text() , you need to give (x,y) location , where you want to put the numbers,
#So here index will give you x pos and data+1 will provide a little gap in y axis.
for index,data in enumerate(menMeans):
    plt.text(x=index , y =data+1 , s=f"{data}" , fontdict=dict(fontsize=20))
plt.tight_layout()
plt.show()

Esto mostrará la figura como:

gráfico de barras con valores en la parte superior

Anirvan Sen
fuente
De todos modos, ¿mover el texto un poco a la izquierda?
S.Ramjit
1
@ S.Ramjitplt.text(x=index , y =data+1 , s=f"{data}" , fontdict=dict(fontsize=20), va='center')
theGtknerd
10

Para la gente de los pandas:

ax = s.plot(kind='barh') # s is a Series (float) in [0,1]
[ax.text(v, i, '{:.2f}%'.format(100*v)) for i, v in enumerate(s)];

Eso es. Alternativamente, para aquellos que prefieren hacer applybucles con enumerate:

it = iter(range(len(s)))
s.apply(lambda x: ax.text(x, next(it),'{:.2f}%'.format(100*x)));

Además, ax.patcheste dará las barras con las que obtendrías ax.bar(...). En caso de que quieras aplicar las funciones de @SaturnFromTitan o técnicas de otros.

tozCSS
fuente
Compruebe si i, v no están invertidos. Quizás debería ser[ax.text(i, v, '{:.2f}%'.format(100*v)) for i, v in enumerate(s)];
Jairo Alves
@JairoAlves este es un diagrama de barras horizontales yv representa la ubicación en el eje x, por lo que debería ser correcto. Consulte también la respuesta aceptada.
tozCSS
Ejemplo con parches for p in ax.patches: ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))
Ichta
1

También necesitaba las etiquetas de las barras, tenga en cuenta que mi eje y tiene una vista ampliada usando límites en el eje y. Los cálculos predeterminados para colocar las etiquetas en la parte superior de la barra aún funcionan usando la altura (use_global_coordinate = False en el ejemplo). Pero quería mostrar que las etiquetas también se pueden colocar en la parte inferior del gráfico en la vista ampliada usando coordenadas globales en matplotlib 3.0.2 . Espero que ayude a alguien.

def autolabel(rects,data):
"""
Attach a text label above each bar displaying its height
"""
c = 0
initial = 0.091
offset = 0.205
use_global_coordinate = True

if use_global_coordinate:
    for i in data:        
        ax.text(initial+offset*c, 0.05, str(i), horizontalalignment='center',
                verticalalignment='center', transform=ax.transAxes,fontsize=8)
        c=c+1
else:
    for rect,i in zip(rects,data):
        height = rect.get_height()
        ax.text(rect.get_x() + rect.get_width()/2., height,str(i),ha='center', va='bottom')

Salida de ejemplo

Haramoz
fuente
0

Estaba tratando de hacer esto con barras de trama apiladas. El código que funcionó para mí fue.

# Code to plot. Notice the variable ax.
ax = df.groupby('target').count().T.plot.bar(stacked=True, figsize=(10, 6))
ax.legend(bbox_to_anchor=(1.1, 1.05))

# Loop to add on each bar a tag in position
for rect in ax.patches:
    height = rect.get_height()
    ypos = rect.get_y() + height/2
    ax.text(rect.get_x() + rect.get_width()/2., ypos,
            '%d' % int(height), ha='center', va='bottom')
Klaifer García
fuente
0

Verifique este enlace Galería Matplotlib Así es como usé el fragmento de código de autolabel.

    def autolabel(rects):
    """Attach a text label above each bar in *rects*, displaying its height."""
    for rect in rects:
        height = rect.get_height()
        ax.annotate('{}'.format(height),
                    xy=(rect.get_x() + rect.get_width() / 2, height),
                    xytext=(0, 3),  # 3 points vertical offset
                    textcoords="offset points",
                    ha='center', va='bottom')
        
temp = df_launch.groupby(['yr_mt','year','month'])['subs_trend'].agg(subs_count='sum').sort_values(['year','month']).reset_index()
_, ax = plt.subplots(1,1, figsize=(30,10))
bar = ax.bar(height=temp['subs_count'],x=temp['yr_mt'] ,color ='g')
autolabel(bar)

ax.set_title('Monthly Change in Subscribers from Launch Date')
ax.set_ylabel('Subscriber Count Change')
ax.set_xlabel('Time')
plt.show()
parth pandey
fuente