1

The error bars overlap in my stacked bar chart. Is there a way to change the x position of the error bar but keep the main bars at the same position?

stacked bar chart

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
import numpy as np
from statistics import mean, stdev, median

colors3 = ['#7ac0f8', '#2196f3', '#1a78c2']
width = 0.6
results = {'Group 1': {'Type A': [24.21, 32.08], 'Type B': [11.35, 6.59], 'Type C': [45.64, 21.87]}, 'Group 2': {'Type A': [19.41, 17.39], 'Type B': [10.16, 8.72], 'Type C': [21.25, 11.57]}, 'Group 3': {'Type A': [11.4, 9.75], 'Type B': [5.73, 6.98], 'Type C': [6.4, 13.38]}}
types = ['Type A', 'Type B', 'Type C']

bottom = [0, 0, 0]
fig, ax = plt.subplots()

for i in range(0, len(types)):
    means = list(map(lambda x: results[x][types[i]][0], results.keys()))
    errs = list(map(lambda x: results[x][types[i]][1], results.keys()))
    ax.bar(results.keys(), means, width, yerr=errs, label=types[i], bottom=bottom, color=colors3[i], error_kw=dict(capsize=5))
    for k in range(0, len(means)):
        bottom[k] = bottom[k] + means[k]

ax.grid(True)
ax.set_axisbelow(True)
plt.legend(types, loc='upper right')
#plt.savefig('img/StackOverflow.png', bbox_inches='tight', dpi=300)
plt.show()
  • Do this by plotting the bars on their own, then plot the errorbars separately, using [`plt.errorbar`](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.errorbar.html) – ACarter Jan 05 '23 at 15:32
  • 2
    Note that even with spread error bars, the resulting plot would be very difficult to interpret by someone else. This is one of the motivations of seaborn not supporting stacked bar plots and preferring dodged bars instead. – JohanC Jan 05 '23 at 15:45

1 Answers1

2

Do this by plotting the bars on their own, then plot the errorbars separately, using plt.errorbar

In order to do this, you'll need to switch to using numerical instead of categorical data (x_vals). I also had to change some of the lists to numpy arrays, to allow elementwise addition.

import matplotlib.pyplot as plt
import numpy as np

colors3 = ['#7ac0f8', '#2196f3', '#1a78c2']
width = 0.6
results = {'Group 1': {'Type A': [24.21, 32.08], 'Type B': [11.35, 6.59], 'Type C': [45.64, 21.87]}, 'Group 2': {'Type A': [19.41, 17.39], 'Type B': [10.16, 8.72], 'Type C': [21.25, 11.57]}, 'Group 3': {'Type A': [11.4, 9.75], 'Type B': [5.73, 6.98], 'Type C': [6.4, 13.38]}}
types = ['Type A', 'Type B', 'Type C']

bottom = np.array([0, 0, 0])
fig, ax = plt.subplots()

for i in range(0, len(types)):
    means = np.array(list(map(lambda x: results[x][types[i]][0], results.keys())))
    errs = list(map(lambda x: results[x][types[i]][1], results.keys()))
    x_vals = np.array([1, 2, 3])
    ax.bar(x_vals, means, width, label=types[i], bottom=bottom, color=colors3[i], error_kw=dict(capsize=5))
    
    ax.errorbar(x_vals - 1/10 + i/10, means+bottom, yerr=errs, linestyle='none', color='black', capsize=5)
    # above line sets the errorbar loctions, adding i/10 each time
    plt.xticks(ticks=x_vals, labels=results.keys())
    # reset the xticks to their names
    
    for k in range(0, len(means)):
        bottom[k] = bottom[k] + means[k]
    print(x_vals, means)

ax.grid(True)
ax.set_axisbelow(True)
plt.legend(types, loc='upper right')
#plt.savefig('img/StackOverflow.png', bbox_inches='tight', dpi=300)
plt.show()

enter image description here

ACarter
  • 5,688
  • 9
  • 39
  • 56