Search code examples
matplotlibbar-charterrorbar

error bars at the limits in matplotlib barchart


I'm trying to get the errorbars to show at the confidence interval's limits, and not in the center.

What I want is this:

enter image description here

but what I'm getting is this:

enter image description here

To plot the bar chart I used this:

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

np.random.seed(12345)

df = pd.DataFrame([np.random.normal(32000,200000,3650), 
                   np.random.normal(43000,100000,3650), 
                   np.random.normal(43500,140000,3650), 
                   np.random.normal(48000,70000,3650)], 
                  index=[1992,1993,1994,1995])
df1 = df.T
df1.columns = ['1992', '1993','1994','1995']
a = df1.describe()
means = a.loc['mean'].values.tolist()
stdevs = a.loc['std'].values.tolist()
counts = a.loc['count'].values.tolist()
index = np.arange(len(df1.columns))

CI = []
for i in range(len(means)):
    CIval = 1.96*stdevs[i]/(counts[i]**(0.5))
    CI.append(CIval)

#print(means, CI)

plt.figure()
fig, ax = plt.subplots(figsize=(10,10))
ax.set_xticks(index)
ax.set_xticklabels(df1.columns)

plt.bar(index, means, xerr = 0.1, yerr=CI)
plt.tight_layout()
plt.show()

Solution

  • The error bars are showing as expected. You have set a 0.1 value for the x error, however in your expected result image, there is no x errorbar so we can remove that. Secondly, we can increase the capsize of your error bars so that they are actually visible by using the capsize= in the call to plt.bar():

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    
    np.random.seed(12345)
    
    df = pd.DataFrame([np.random.normal(32000,200000,3650),
                       np.random.normal(43000,100000,3650),
                       np.random.normal(43500,140000,3650),
                       np.random.normal(48000,70000,3650)],
                      index=[1992,1993,1994,1995])
    df1 = df.T
    df1.columns = ['1992', '1993','1994','1995']
    a = df1.describe()
    means = a.loc['mean'].values.tolist()
    stdevs = a.loc['std'].values.tolist()
    counts = a.loc['count'].values.tolist()
    index = np.arange(len(df1.columns))
    
    CI = []
    for i in range(len(means)):
        CIval = 1.96*stdevs[i]/(counts[i]**(0.5))
        CI.append(CIval)
    
    fig, ax = plt.subplots(figsize=(10,10))
    ax.set_xticks(index)
    ax.set_xticklabels(df1.columns)
    
    plt.bar(index, means, yerr=CI, capsize=10)
    plt.tight_layout()
    plt.show()
    

    enter image description here