Medulla Oblongata
Medulla Oblongata

Reputation: 3961

Plotting percentile values as errorbars on seaborn barplot

I want to plot a bar chart on seaborn and include custom errorbars. My MWE is

import pandas as pd
import seaborn as sns

w = pd.DataFrame(data={'length': [40,35,34,40,38,39,38,44,40,39,35,46],
                       'species': ['A','A','A','A','B','B','B','B','C','C','C','C'],
                       'type': ['today','avg','10pc','90pc','today','avg','10pc','90pc','today','avg','10pc','90pc']
                      },
                )
w['Date'] = pd.to_datetime('2021-09-20')
w.set_index('Date',inplace=True)

w0 = w.loc[(w.type=='today') | (w.type=='avg')] # average length and today's length
w1 = w.loc[(w.type=='10pc') | (w.type=='90pc')] # 10th and 90th percentile

fig, ax = plt.subplots(figsize=(8,5))
y = sns.barplot(x=w0['species'], y=w0['length'], hue=w0['type'], yerr=w1['10pc','90pc'], capsize=.2) 
y.set_title(w0.index[0].strftime('%d %b %Y'), fontsize=16)
y.set_xlabel('species', fontsize=14)
y.set_ylabel('length (cm)', fontsize=14)
y.grid(axis='y', lw=0.5)

plt.show()

where today is today's length measurement, avg is the mean measurement, and 10pc and 90pc are the 10th and 90th percentile values. I tried setting yerr in the barplot command, but this doesn't work. I'm not sure how to configure seaborn to accept the percentile values.

I want to plot 10pc and 90pc for the avg bars for each species. This is what I'm aiming for (black bars drawn in myself):

enter image description here

Upvotes: 0

Views: 1320

Answers (1)

hajben
hajben

Reputation: 321

This is my take, using pandas' plotting functionality, based on this post's accepted answer:

errors = w1.pivot_table(columns=[w1.index,'species'],index='type',values=['length']).values
avgs = w0.length[w0.type=='avg'].values
bars = np.stack((np.absolute(errors-avgs), np.zeros([2,w1.species.unique().size])), axis=0)

fig, ax = plt.subplots(figsize=(8,5))
w0.pivot(index='species', columns='type', values='length').plot(kind='bar', yerr=bars, ax=ax)
ax.set_title(w0.index[0].strftime('%d %b %Y'), fontsize=16)
ax.set_xlabel('species', fontsize=14)
ax.set_ylabel('length (cm)', fontsize=14)
ax.grid(axis='y', lw=0.5)

This is what the resulting figure looks like:

enter image description here

Upvotes: 1

Related Questions