# Unable to generate error bars with seaborn

This is the csv:

run,testcase,algorithm,group,avg_weightedcost,std_weight
1,1,QI,0,20007037.36,0
2,1,Q2,0,60000000,3.76E-09
3,1,Q4,0,181801581.2,13353630.74
4,1,Q3,0,585605657.3,54852458.59
6,1,QI,1,10003518.68,0
7,1,Q2,1,292802828.7,2.00E+01
8,1,Q4,1,90900790.6,13353630.74
9,1,Q3,1,292802828.7,27426229.3


This is the code and graph generated:

g = sns.barplot(y="algorithm", x="avg_weightedcost", hue="group",
capsize=.2, data=df)


This is how I tried to add the error bar:

g = sns.barplot(y="algorithm", x="avg_weightedcost", hue="group",
xerr="std_weight", capsize=.2, data=df)


This is the error:

ValueError: err must be [ scalar | N, Nx1 or 2xN array-like ]


Modified:

csv file:

run,testcase,algorithm,group,avg_weightedcost,std_weight,avg,err
1,1,QI,0.00,20007037.36,0.00,100.00,5.00
2,1,Q2,0.00,60000000.00,0.00,50.00,20.00
3,1,Q4,0.00,181801581.20,13353630.74,50.00,10.00
4,1,Q3,0.00,585605657.30,54852458.59,20.00,1.00
6,1,QI,1.00,10003518.68,0.00,20.00,20.00
7,1,Q2,1.00,292802828.65,20.00,30.00,10.00
8,1,Q4,1.00,90900790.60,13353630.74,10.00,10.00
9,1,Q3,1.00,292802828.65,27426229.30,50.00,20.00


code:

g = sns.barplot(x=data2['avg_weightedcost'], y=data2['algorithm'],
hue=data2['group'])

g.errorbar(x=data2['avg_weightedcost'], y=data2['algorithm'],
xerr=data2['std_weight'], ecolor='red', linewidth=0, capsize=15)


Error:

ValueError: could not convert string to float: 'Q3'

• According to the docs you can use factorplots when you have cats, seaborn.pydata.org/generated/seaborn.barplot.html May 18 '18 at 16:40
• I tried g = sns.factorplot(y="algorithm", x="avg_weightedcost", hue="group", col="testcase", data=df2, kind="bar", size=7, aspect=1) but i still cannot get the error bar working
– MTA
May 18 '18 at 16:41

I found this question when trying to find a way to add my own precalculated, custom error bars (standard deviations) to a Seaborn barplot with grouped values. I finally managed to find a workaround... The idea is to duplicate the observations drawing from a normal distribution with the desired mean and standard deviation. Then, the built-in "ci" option in sns.barplot does the rest. Not the cleanest solution... but it does the trick (at least for small datasets). An example:

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

#duplicate observations to get good std bars
dfCopy = dfBarPlot.copy()
duplicates = 30 # increase this number to increase precision
for index, row in dfBarPlot.iterrows():
for times in range(duplicates):
new_row = row.copy()
new_row['Y'] = np.random.normal(row['Y'],row['precomputed_std'])
dfCopy = dfCopy.append(new_row, ignore_index=True)

# Now Seaborn does the rest
sns.set_style("whitegrid")
fig = sns.barplot(x='X',
y='Y',
hue='Cases',
ci='sd',
data=dfCopy)

plt.legend(loc='upper right')
sns.set(rc={'figure.figsize':(8,5)})
plt.show()


• wow, what a crazy hack! Thanks Aug 13 '20 at 13:06

Try this:

g = sns.barplot(y="algorithm", x="avg_weightedcost", hue="group",
xerr=df[std_weight]*1, capsize=.2, data=df)


Hope it helps

Update 2020-01-15

The barplot_err function is now available as part of the hhpy package

Disclaimer: I am the creator of hhpy

import hhpy.plotting as hpt
import pandas as pd

fig,ax = plt.subplots(figsize=(9,9),nrows=2)
hpt.barplot_err(y="algorithm", x="avg_weightedcost", xerr="std_weight", hue="group",
capsize=.2, data=df, ax=ax[0])
barplot_err(x="algorithm", y="avg_weightedcost", yerr="std_weight", hue="group",
capsize=.2, data=df, ax=ax[1])
plt.show()


This answer is based on 1gnaci0 7's. But you don't need to create 30 duplicates by drawing from a normal distribution. If your only goal is showing the error bars you only need 3 duplicates (x-xerr, x, x+xerr) [respective for y] and you're good to go (and most of all the bars are exact!).

So I turned it into a function that works for both x and y directions and 'only' triples the size of the initial dataframe.

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

def barplot_err(x, y, xerr=None, yerr=None, data=None, **kwargs):

_data = []
for _i in data.index:

_data_i = pd.concat([data.loc[_i:_i]]*3, ignore_index=True, sort=False)
_row = data.loc[_i]
if xerr is not None:
_data_i[x] = [_row[x]-_row[xerr], _row[x], _row[x]+_row[xerr]]
if yerr is not None:
_data_i[y] = [_row[y]-_row[yerr], _row[y], _row[y]+_row[yerr]]
_data.append(_data_i)

_data = pd.concat(_data, ignore_index=True, sort=False)

_ax = sns.barplot(x=x,y=y,data=_data,ci='sd',**kwargs)

return _ax

fig,ax = plt.subplots(figsize=(9,9),nrows=2)
barplot_err(y="algorithm", x="avg_weightedcost", xerr="std_weight", hue="group",
capsize=.2, data=df, ax=ax[0])
barplot_err(x="algorithm", y="avg_weightedcost", yerr="std_weight", hue="group",
capsize=.2, data=df, ax=ax[1])
plt.show()


Same idea as @1gnaci0 7 but a faster way of duplicating rows:

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

duplicates=1000