web-dev-qa-db-fra.com

Comment ajouter des pourcentages au-dessus des barres dans Seaborn?

Compte tenu du tracé de comptage suivant, comment puis-je placer des pourcentages au-dessus des barres?

import seaborn as sns
sns.set(style="darkgrid")
titanic = sns.load_dataset("titanic")
ax = sns.countplot(x="class", hue="who", data=titanic)

enter image description here

Par exemple, pour "First", je veux que le total First Men/total First, le total First Women/total First et le total First Children/total First soient affichés en haut de leurs barres respectives.

Veuillez me faire savoir si mon explication n'est pas claire.

Merci!

24
I am not George

sns.barplot ne renvoie pas explicitement les valeurs du diagramme à barres comme matplotlib.pyplot.bar le fait (voir le dernier paragraphe), mais si vous n'avez rien tracé d'autre, vous pouvez risquer de supposer que tous les patches dans les axes sont vos valeurs. Ensuite, vous pouvez utiliser les sous-totaux que la fonction de graphique à barres a calculé pour vous:

from matplotlib.pyplot import show
import seaborn as sns
sns.set(style="darkgrid")
titanic = sns.load_dataset("titanic")
total = float(len(titanic)) # one person per row 
#ax = sns.barplot(x="class", hue="who", data=titanic)
ax = sns.countplot(x="class", hue="who", data=titanic) # for Seaborn version 0.7 and more
for p in ax.patches:
    height = p.get_height()
    ax.text(p.get_x()+p.get_width()/2.,
            height + 3,
            '{:1.2f}'.format(height/total),
            ha="center") 
show()

produit

Countplot

Une autre approche consiste à effectuer la sous-sommation explicitement, par exemple avec l'excellent pandas, et tracer avec matplotlib, et faire le style vous-même. (Bien que vous puissiez obtenir beaucoup de style à partir du contexte sns même en utilisant les fonctions de traçage matplotlib. Essayez-le -)

45
cphlewis

Avec l'aide de la solution cphlewis , j'ai réussi à mettre les pourcentages corrects en haut du tableau, donc les classes se résument à un.

for index, category in enumerate(categorical):
    plt.subplot(plot_count, 1, index + 1)

    order = sorted(data[category].unique())
    ax = sns.countplot(category, data=data, hue="churn", order=order)
    ax.set_ylabel('')

    bars = ax.patches
    half = int(len(bars)/2)
    left_bars = bars[:half]
    right_bars = bars[half:]

    for left, right in Zip(left_bars, right_bars):
        height_l = left.get_height()
        height_r = right.get_height()
        total = height_l + height_r

        ax.text(left.get_x() + left.get_width()/2., height_l + 40, '{0:.0%}'.format(height_l/total), ha="center")
        ax.text(right.get_x() + right.get_width()/2., height_r + 40, '{0:.0%}'.format(height_r/total), ha="center")

enter image description here

Cependant, la solution suppose qu'il y a 2 options (homme, femme) contre 3 (homme, femme, enfant).

Puisque Axes.patches sont classés de manière étrange (d'abord toutes les barres bleues, puis toutes les barres vertes, puis toutes les barres rouges), vous devez les diviser et les recompresser en conséquence.

1
Lord Zsolt