'Display count on top of seaborn barplot

I have a dataframe that looks like:

  User   A       B     C
   ABC   100    121   OPEN
   BCD   200    255   CLOSE
   BCD   500    134   OPEN
   DEF   600    125   CLOSE
   ABC   900    632   OPEN
   ABC   150    875   CLOSE
   DEF   690    146   OPEN

I am trying to display a countplot on column 'User'. The code is as follows:

fig, ax1 = plt.subplots(figsize=(20,10))
graph = sns.countplot(ax=ax1,x='User', data=df)
graph.set_xticklabels(graph.get_xticklabels(),rotation=90)
for p in graph.patches:
    height = p.get_height()
    graph.text(p.get_x()+p.get_width()/2., height + 0.1,
        'Hello',ha="center")

The output looks like:

However, I want to replace string 'Hello' with the value_counts of column 'User'. When I add the code to add label to graph :

for p in graph.patches:
    height = p.get_height()
    graph.text(p.get_x()+p.get_width()/2., height + 0.1,
        df['User'].value_counts(),ha="center")

I get the output as:



Solution 1:[1]

New in matplotlib 3.4.0

We can now automatically annotate bar plots with the built-in Axes.bar_label, so all we need to do is access/extract the seaborn plot's Axes.

Seaborn offers several ways to plot counts, each with slightly different count aggregation and Axes handling:

  • seaborn.countplot (most straightforward)

    This automatically aggregates counts and returns an Axes, so just directly label ax.containers[0]:

    ax = sns.countplot(x='User', data=df)
    ax.bar_label(ax.containers[0])
    
  • seaborn.catplot (kind='count')

    This plots a countplot onto a facet grid, so extract the Axes from the grid before labeling ax.containers[0]:

    g = sns.catplot(x='User', kind='count', data=df)
    for ax in g.axes.flat:
        ax.bar_label(ax.containers[0])
    
  • seaborn.barplot

    This returns an Axes but does not aggregate counts, so first compute Series.value_counts before labeling ax.containers[0]:

    counts = df['User'].value_counts().rename_axis('user').reset_index(name='count')
    
    ax = sns.barplot(x='user', y='count', data=counts)
    ax.bar_label(ax.containers[0])
    

If you are using hue:

  • hue plots will contain multiple bar containers, so ax.containers will need to be iterated:

    ax = sns.countplot(x='User', hue='C', data=df)
    for container in ax.containers:
        ax.bar_label(container)
    

seaborn bars with labels

Solution 2:[2]

df['User'].value_counts() will return a Series containing counts of unique values of the column User.

Without analyzing in much detail your code, you could correct it by indexing the result of value_counts with a counter:

fig, ax1 = plt.subplots(figsize=(20,10))
graph = sns.countplot(ax=ax1,x='User', data=df)
graph.set_xticklabels(graph.get_xticklabels(),rotation=90)
i=0
for p in graph.patches:
    height = p.get_height()
    graph.text(p.get_x()+p.get_width()/2., height + 0.1,
        df['User'].value_counts()[i],ha="center")
    i += 1

With your sample data, it produces the following plot:

enter image description here

As suggested by @ImportanceOfBeingErnest, the following code produces the same output with simpler code, using the height variable itself instead of the value_counts indexed:

fig, ax1 = plt.subplots(figsize=(20,10))
graph = sns.countplot(ax=ax1,x='User', data=df)
graph.set_xticklabels(graph.get_xticklabels(),rotation=90)
for p in graph.patches:
    height = p.get_height()
    graph.text(p.get_x()+p.get_width()/2., height + 0.1,height ,ha="center")

Solution 3:[3]

other solution

#data
labels=data['Sistema Operativo'].value_counts().index
values=data['Sistema Operativo'].value_counts().values

plt.figure(figsize = (15, 8))
ax = sns.barplot(x=labels, y=values)
for i, p in enumerate(ax.patches):
    height = p.get_height()
    ax.text(p.get_x()+p.get_width()/2., height + 0.1, values[i],ha="center")

Chart Image

Solution 4:[4]

Note: This solution does not try to show the count on top of the bar. Instead, this simple solution will print the values inside the bar. This may be an elegant solution for some occasions.

import seaborn as sns

ax=sns.countplot(x=df['category'], data=df);
for p in ax.patches:
    ax.annotate(f'\n{p.get_height()}', (p.get_x()+0.2, p.get_height()), ha='center', va='top', color='white', size=18)

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 NoƩ Melo Locumber
Solution 4 Dharman