Seaborn: countplot() with frequencies

You can do this by making a twinx axes for the frequencies. You can switch the two y axes around so the frequencies stay on the left and the counts on the right, but without having to recalculate the counts axis (here we use tick_left() and tick_right() to move the ticks and set_label_position to move the axis labels

You can then set the ticks using the matplotlib.ticker module, specifically ticker.MultipleLocator and ticker.LinearLocator.

As for your annotations, you can get the x and y locations for all 4 corners of the bar with patch.get_bbox().get_points(). This, along with setting the horizontal and vertical alignment correctly, means you don’t need to add any arbitrary offsets to the annotation location.

Finally, you need to turn the grid off for the twinned axis, to prevent grid lines showing up on top of the bars (ax2.grid(None))

Here is a working script:

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import matplotlib.ticker as ticker

# Some random data
dfWIM = pd.DataFrame({'AXLES': np.random.normal(8, 2, 5000).astype(int)})
ncount = len(dfWIM)

ax = sns.countplot(x="AXLES", data=dfWIM, order=[3,4,5,6,7,8,9,10,11,12])
plt.title('Distribution of Truck Configurations')
plt.xlabel('Number of Axles')

# Make twin axis

# Switch so count axis is on right, frequency on left

# Also switch the labels over

ax2.set_ylabel('Frequency [%]')

for p in ax.patches:
    ax.annotate('{:.1f}%'.format(100.*y/ncount), (x.mean(), y), 
            ha="center", va="bottom") # set the alignment of the text

# Use a LinearLocator to ensure the correct number of ticks

# Fix the frequency range to 0-100

# And use a MultipleLocator to ensure a tick spacing of 10

# Need to turn the grid on ax2 off, otherwise the gridlines end up on top of the bars


enter image description here

Leave a Comment