Search code examples
rggplot2bar-charterrorbarstacked-bar-chart

Add error bar to ggplot2 stacked barplot, without using dodge


I can find examples of adding error bars to dodged barplots (e.g. here).

However, is it possible to denote both a stacked barplot, with a single error bar at the top of each bar showing overall error? For example, like this middle plot below? How would I add the red error bars?

enter image description here

My basic ggplot2 code is here:

ggplot(sample, aes(x=strategy_short, y=baseline, fill=income)) +
  geom_bar(position="stack", stat="identity") +
  facet_grid(~scenario_capacity)

And my data are below:

income,scenario_capacity,strategy_short,baseline,high,low
LIC,50_gb_month,4G_f,0.260317022,0.326222444,0.234391846
LIC,50_gb_month,5G_f,0.124212858,0.146834332,0.115607428
LIC,50_gb_month,4G_w,0.266087059,0.331992481,0.240156101
LIC,50_gb_month,5G_w,0.129977113,0.152604368,0.121371683
LMIC,50_gb_month,4G_f,0.83300281,0.981024297,0.770961424
LMIC,50_gb_month,5G_f,0.527561846,0.56027992,0.517383821
LMIC,50_gb_month,4G_w,0.837395381,0.985564298,0.77528317
LMIC,50_gb_month,5G_w,0.53198477,0.564819922,0.521741702
UMIC,50_gb_month,4G_f,2.084363642,2.161110527,2.047796949
UMIC,50_gb_month,5G_f,1.644845928,1.667321898,1.634737764
UMIC,50_gb_month,4G_w,2.08822286,2.165063696,2.051605578
UMIC,50_gb_month,5G_w,1.648696474,1.67124905,1.638559402
HIC,50_gb_month,4G_f,1.016843718,1.026058625,1.010465168
HIC,50_gb_month,5G_f,0.820046245,0.823345129,0.81792777
HIC,50_gb_month,4G_w,1.019669475,1.028904617,1.013290925
HIC,50_gb_month,5G_w,0.823000642,0.82634578,0.820861932

Whenever I try to use an aggregated dataframe to feed to geom_errorbar, as below, I end up with an error message ('object 'income' not found').

sample_short <- sample %>%
  group_by(scenario_capacity, strategy_short) %>%
  summarize(
    low = sum(low),
    baseline = sum(baseline),
    high = sum(high),
  )

ggplot(sample, aes(x=strategy_short, y=baseline, fill=income)) +
  geom_bar(position="stack", stat="identity") +
  geom_errorbar(data=sample_short, aes(y = baseline, ymin = low, ymax = high)) +
  facet_grid(~scenario_capacity)

Solution

  • You need to include income in your summary stats, like so:

    (df being your dataframe: avoid naming objects with function names like sample):

    df_errorbar <- 
      df |>
      group_by(scenario_capacity, strategy_short) |>
      summarize(
        income = first(income),
        low = sum(low),
        baseline = sum(baseline),
        high = sum(high)
      )
    
    df |>
      ggplot(aes(x=strategy_short, y=baseline, fill=income)) +
      geom_bar(position="stack", stat="identity") +
      geom_errorbar(data = df_errorbar, aes(y = baseline, ymin = low, ymax = high)) +
      facet_grid(~scenario_capacity)
    

    take care about appropriate grouping when desiring an overall "error"

    error bars