Barplot in python with % value in Y axis and count value in text on top of the bars

45 Views Asked by At

I have a df such as :

data = {
    'class': ['First', 'First', 'First', 'Second', 'Second', 'Second', 'Third', 'Third', 'Third'],
    'who': ['child', 'man', 'woman', 'child', 'man', 'woman', 'child', 'man', 'woman'],
    'survived': [5, 42, 89, 19, 8, 60, 25, 38, 56],
    'Percentage': [10.204082, 47.727273, 43.414634, 38.775510, 9.090909, 29.268293, 51.020408, 43.181818, 27.317073]
}

# Create DataFrame
df = pd.DataFrame(data)


    class    who  survived  Percentage
0   First  child         5   10.204082
1   First    man        42   47.727273
2   First  woman        89   43.414634
3  Second  child        19   38.775510
4  Second    man         8    9.090909
5  Second  woman        60   29.268293
6   Third  child        25   51.020408
7   Third    man        38   43.181818
8   Third  woman        56   27.317073

Could someone help me to write a code with seaborn where :

I want a barplot grouped by "class" in that order : ["First","Second","Third"] and were the bar plots are also grouped such as : ["child","man","woman"].

In the y axis should be displayed the percentage of survived .

And I would like for each bar to display in their top the actual 'survived' value.

In the end the plot should look like that :

enter image description here

Here is the code I got so far :

# Plot
ax = sns.barplot(x='class', y='Percentage', hue='who', data=data, estimator=sum, ci=None)
ax.set(ylabel='Survived Count', title='Survived Count and Percentage')
1

There are 1 best solutions below

0
Trenton McKinney On BEST ANSWER

As per the duplicate:

fig, ax = plt.subplots(figsize=(9, 7))
sns.barplot(x='class', y='Percentage', hue='who', data=df, ax=ax)
sns.move_legend(ax, bbox_to_anchor=(1, 0.5), loc='center left', frameon=False)

# get the unique values for hue
hue_col = df.who.unique()

# iterate through each group of containers - in order by hue groups
for c, col in zip(ax.containers, hue_col):
    
    # use the column and bar height to get the correct value for name
    labels = [f"{df.loc[(df.who.eq(col) & df.Percentage.eq(h)), 'survived'].iloc[0]}" if (h := v.get_height()) > 0 else '' for v in c ]
 
    # add the survived annotation to the top of the bar
    ax.bar_label(c, labels=labels, padding=3)  # rotation=90 if needed

    # pad the spacing between the number and the edge of the figure
    ax.margins(y=0.1)

enter image description here