close

How to add percentages on top of bars in seaborn

Hello Guys, How are you all? Hope You all Are Fine. Today We Are Going To learn about How to add percentages on top of bars in seaborn in Python. So Here I am Explain to you all the possible Methods here.

Without wasting your time, Let’s start This Article.

Table of Contents

How to add percentages on top of bars in seaborn?

  1. How to add percentages on top of bars in seaborn?

    The seaborn.catplot organizing function returns a FacetGrid, which gives you access to the fig, the ax, and its patches.

  2. add percentages on top of bars in seaborn

    The seaborn.catplot organizing function returns a FacetGrid, which gives you access to the fig, the ax, and its patches.

Method 1

The seaborn.catplot organizing function returns a FacetGrid, which gives you access to the fig, the ax, and its patches. If you add the labels when nothing else has been plotted you know which bar-patches came from which variables. From @LordZsolt’s answer I picked up the order argument to catplot: I like making that explicit because now we aren’t relying on the barplot function using the order we think of as default.

import seaborn as sns
from itertools import product

titanic = sns.load_dataset("titanic")

class_order = ['First','Second','Third'] 
hue_order = ['child', 'man', 'woman']
bar_order = product(class_order, hue_order)

catp = sns.catplot(data=titanic, kind='count', 
                   x='class', hue='who',
                   order = class_order, 
                   hue_order = hue_order )

# As long as we haven't plotted anything else into this axis,
# we know the rectangles in it are our barplot bars
# and we know the order, so we can match up graphic and calculations:

spots = zip(catp.ax.patches, bar_order)
for spot in spots:
    class_total = len(titanic[titanic['class']==spot[1][0]])
    class_who_total = len(titanic[(titanic['class']==spot[1][0]) & 
        (titanic['who']==spot[1][1])])
    height = spot[0].get_height() 
    catp.ax.text(spot[0].get_x(), height+3, '{:1.2f}'.format(class_who_total/class_total))

    #checking the patch order, not for final:
    #catp.ax.text(spot[0].get_x(), -3, spot[1][0][0]+spot[1][1][0])

produces

barplot of three-by-three variable values, with subset calculations as text labels

An alternate approach is to do the sub-summing explicitly, e.g. with the excellent pandas, and plot with matplotlib, and also do the styling yourself. (Though you can get quite a lot of styling from sns context even when using matplotlib plotting functions. Try it out — )

Method 2

I managed to put the correct percentages on top of the chart, so the classes sum up to one.

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

However, the solution assumes there are 2 options (man, woman) as opposed to 3 (man, woman, child).

Since Axes.patches are ordered in a weird way (first all the blue bars, then all the green bars, then all red bars), you would have to split them and zip them back together accordingly.

Conclusion

It’s all About this issue. Hope all Methods helped you a lot. Comment below Your thoughts and your queries. Also, Comment below which Method worked for you? Thank You.

Also, Read