0

I have a 2x2 subplot consisting of 4 Seaborn bar charts. I would like to add the value of every bar in each chart to the top of each bar.

I can add text and manually position it, which I have tried, but I know this is inefficient and there must be a better way.

I can't seem to figure out how to get the solutions other people have found for individual barcharts to work on the subplot.

Here is my code:

Data:

vis = pd.DataFrame({'Win %': [52.631579, 59.736842, 50.657895, 42.609649],
                    'Made Playoffs': [7,12,8,4],
                    'Won NFC Championship': [0,2,3,0],
                    'Won Super Bowl': [0,1,2,0]},
                    index=['Cowboys','Eagles','Giants','Redskins'])
vis = test.reset_index()
vis = test.rename(columns={'index':'Team'})

Plotting:

fig, ((ax1,ax2), (ax3,ax4)) = plt.subplots(2,2, sharex=True, sharey=False, figsize=(10,10))

fig.suptitle('NFC East Division Rivals, 2000-2018')
fig.subplots_adjust(wspace=0.5, hspace=0.3)

for ax in plt.gcf().get_axes():
    for label in ax.get_xticklabels() + ax.get_yticklabels():
        label.set_visible(True)

sns.set_style("darkgrid", {'font.sans-serif':'sans-serif', 'text.color':'#1e1e1e'})

# Win %
sns.barplot(x='Team',y='Win %',data=vis, palette=colors, 
            edgecolor=edges, linewidth=2, ax=ax1)

ax1.title.set_text('Average Win %')
ax1.set_ylabel('')
ax1.set_xlabel('')

for i, v in enumerate(df['Win %']):
    ax1.text(v + 3, i +.25, str(v))


# Playoff Appearances
sns.barplot(x='Team', y='Made Playoffs', data=vis, palette=colors,
           edgecolor=edges, linewidth=2, ax=ax2, estimator=sum)

ax2.title.set_text('Playoff Appearances')
ax2.set_ylabel('')
ax2.set_xlabel('')

# NFC Championships
sns.barplot(x='Team', y='Won NFC Championship', data=vis, palette=colors,
           edgecolor=edges, linewidth=2, ax=ax3, estimator=sum)

ax3.title.set_text('NFC Championships Won')
ax3.set_ylabel('')
ax3.set_xlabel('')
ax3.set_yticks([0, 1, 2, 3])

# Super Bowls
sns.barplot(x='Team', y='Won Super Bowl', data=vis, palette=colors,
           edgecolor=edges, linewidth=2, ax=ax4, estimator=sum)

ax4.title.set_text('Super Bowls Won')
ax4.set_ylabel('')
ax4.set_xlabel('')
ax4.set_yticks([0, 1, 2])

plt.show()

I get the Subplots I am expecting, but I have no idea how to add a "call out" value displaying the value of the bar above each and every bar in each and every subplot.

So, for example, in the Average Win % bar chart, there should be a "52.6%" above the Cowboys bar, a "59.7%" above the Eagles bar, and so on.

The y-axes are all in different units, too.

Any help is greatly appreciated!

n0ro
  • 477
  • 4
  • 11
  • 2
    Take a look at this [answer](https://stackoverflow.com/a/56397528/10620028). I provided some code to label the bars on a plot dynamically. – iamchoosinganame May 31 '19 at 18:02
  • Ahh, yes! Just what I needed! Cheers! If you can put this as a response, I can mark it as answer. Thanks so much! – n0ro May 31 '19 at 18:08
  • Also: is there a way to add some padding between the value and the bars so that the number is not actually touching the top of the bar? – n0ro May 31 '19 at 18:14
  • 1
    Yes just add a constant value to the y-value. Something like `bar.get_height()+.01` You can adjust the value you're adding to change how high the offset is. – iamchoosinganame May 31 '19 at 18:15
  • I would recommend using `annotate` instead of `text` and apply some offset just as shown in [the matplotlib example](https://matplotlib.org/gallery/lines_bars_and_markers/barchart.html). – ImportanceOfBeingErnest May 31 '19 at 23:08

0 Answers0