web-dev-qa-db-fra.com

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

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

Parcelle actuelle:

enter image description here

Ce que j'essaie d'obtenir:

enter image description here

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
46

Ajouter: 

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

résultat:

enter image description here

Les valeurs de y v sont à la fois les valeurs d'emplacement x et de chaîne pour ax.text, et le diagramme en barres a une métrique de 1 pour chaque barre, de sorte que l'énumération i est l'emplacement en y. 

93
cphlewis

J'ai remarqué exemple d'api code 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()

sortie:

 enter image description here

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

17
Franck Dernoncourt

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

EDIT: Au fur et à mesure que j'apprécie beaucoup cet ancien fil de discussion, je souhaite également partager une solution mise à jour (en rassemblant mes deux fonctions précédentes et en décidant automatiquement s'il s'agit d'un tracé à barres ou à barres):

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 parcelles à barres régulières:

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 parcelles à 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)
8
SaturnFromTitan

Pour ceux qui souhaitent avoir leur label à la base de leurs barres, il suffit de diviser v par la valeur du label 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 tout à fait en bas)

Pour obtenir un résultat comme celui-ci:  enter image description here

7
Skromak

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 le chiffre comme suit:

histogramme avec les valeurs en haut

1
Anirvan Sen

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 ça ..__ Alternativement, pour ceux qui préfèrent apply au lieu de boucler avec énumérer:

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

De plus, ax.patches vous donnera les barres que vous obtiendrez avec ax.bar(...). Si vous souhaitez appliquer les fonctions de @SaturnFromTitan ou les techniques de tiers.

1
tozCSS

J'avais aussi besoin des étiquettes, notez que mon axe des ordonnées dispose d'une vue zoomée utilisant des limites sur l'axe des ordonnées. Les calculs par défaut permettant de placer les étiquettes au-dessus de la barre fonctionnent toujours avec height (use_global_coordinate = False dans l'exemple). Mais je voulais montrer que les étiquettes peuvent également être placées dans la partie inférieure du graphique en vue agrandie en utilisant les coordonnées globales dans matplotlib 3.0.2 . J'espère que ça 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')

 Example output

0
Haramoz