Comment afficher la valeur de la barre sur chaque barre avec pyplot.barh ()?

106

J'ai généré un graphique à barres, comment puis-je afficher la valeur de la barre sur chaque barre?

Graphique actuel:

entrez la description de l'image ici

Ce que j'essaye d'obtenir:

entrez la description de l'image ici

Mon code:

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
la source

Réponses:

173

Ajouter:

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

résultat:

entrez la description de l'image ici

Les valeurs y vsont à la fois l'emplacement x et les valeurs de chaîne pour ax.text, et le barplot a une métrique de 1 pour chaque barre, donc l'énumération iest l'emplacement y.

cphlewis
la source
11
peut-être remplacer utiliser va = 'center', au lieu de "i + .25" pour l'alignement horizontal
mathause
11
plt.text(v, i, " "+str(v), color='blue', va='center', fontweight='bold')
João Cartucho
Comment puis-je supprimer la sortie de texte dans un notebook Jupyter? ";" à la fin ne fonctionne pas.
Ralf Hundewadt
Si je veux imprimer QUARTIER au-dessus de la barre et même pour toutes les barres baove, plutôt à gauche, que faut-il faire. essayé et rechercher de nombreux endroits mais aucun indice jusqu'à présent.
Rishi Bansal
@RalfHundewadt vient de mettre une plt.show()clause à la fin. Par exemple: df.plot(); plt.show()
Jairo Alves
36

J'ai remarqué que l' exemple de code api contient un exemple de graphique à barres avec la valeur de la barre affichée sur chaque barre:

"""
========
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()

production:

entrez la description de l'image ici

FYI Quelle est l'unité de hauteur variable en "barh" de matplotlib? (à partir de maintenant, il n'y a pas de moyen facile de définir une hauteur fixe pour chaque barre)

Franck Dernoncourt
la source
1
Il semble que get_x () arrondit le nombre vers le haut même si le x d'origine a des décimales. Comment obtenir plus de décimales à afficher?
ru111
1
tard à la fête, mais pour quiconque l'utilise en utilisant hauteur + 0,1 au lieu de 1,05 * hauteur dans la fonction d'autolabel crée un écart cohérent entre la barre et le texte
jnPy
19

Pour tous ceux qui souhaitent avoir leur étiquette à la base de leurs barres, divisez simplement v par la valeur de l'étiquette comme ceci:

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

(note: j'ai ajouté 100 donc ce n'était pas absolument en bas)

Pour obtenir un résultat comme celui-ci: entrez la description de l'image ici

Skromak
la source
Sûrement v == labels[i]et ainsi la troisième et la quatrième ligne pourraient simplement être 101, v?
C'estNOTALie.
14

Je sais que c'est un vieux fil de discussion, mais j'ai atterri ici plusieurs fois via Google et je pense qu'aucune réponse n'est encore vraiment satisfaisante. Essayez d'utiliser l'une des fonctions suivantes:

EDIT : Au fur et à mesure que j'obtiens des likes sur cet ancien fil, je veux également partager une solution mise à jour (en gros, rassembler mes deux fonctions précédentes et décider automatiquement s'il s'agit d'un tracé à barres ou 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)

Vous pouvez maintenant les utiliser pour les graphiques à barres normaux:

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)

ou pour les graphiques à barres 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)
SaturneDeTitan
la source
14

Utilisez plt.text () pour mettre du texte dans le tracé.

Exemple:

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

Cela montrera la figure comme:

graphique à barres avec des valeurs en haut

Anirvan Sen
la source
Quoi qu'il en soit, décaler le texte un peu vers la gauche?
S.Ramjit
1
@ S.Ramjitplt.text(x=index , y =data+1 , s=f"{data}" , fontdict=dict(fontsize=20), va='center')
theGtknerd
10

Pour les 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)];

C'est tout. Alternativement, pour ceux qui préfèrent applyle bouclage avec enumerate:

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

En outre, ax.patchesvous donnera les barres avec lesquelles vous obtiendrez ax.bar(...). Au cas où vous voudriez appliquer les fonctions de @SaturnFromTitan ou des techniques d'autres.

tozCSS
la source
Veuillez vérifier si i, v ne sont pas inversés. Peut-être que ça devrait être[ax.text(i, v, '{:.2f}%'.format(100*v)) for i, v in enumerate(s)];
Jairo Alves
@JairoAlves c'est un graphique à barres horizontales et v représente l'emplacement sur l'axe des x, donc il devrait être correct. Veuillez également consulter la réponse acceptée.
tozCSS
Exemple avec des correctifs for p in ax.patches: ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))
Ichta le
1

J'avais également besoin des étiquettes de barre, notez que mon axe y a une vue agrandie en utilisant des limites sur l'axe y. Les calculs par défaut pour placer les étiquettes au-dessus de la barre fonctionnent toujours en utilisant la hauteur (use_global_coordinate = False dans l'exemple). Mais je voulais montrer que les étiquettes peuvent également être placées en bas du graphique en vue agrandie en utilisant les coordonnées globales dans matplotlib 3.0.2 . J'espère que cela aidera quelqu'un.

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

Exemple de sortie

Haramoz
la source
0

J'essayais de faire cela avec des barres de tracé empilées. Le code qui a fonctionné pour moi était.

# 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 Garcia
la source
0

Vérifiez ce lien Galerie Matplotlib Voici comment j'ai utilisé l'extrait de code de l'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
la source