rggplot2colorsbar-charterrorbar

Customize error bar colors for grouped barplot


I have a data frame for making a barplot by "question", where bars are grouped by "group" variable. I'd also like to customize the colors of the error bars according to the ci_color column. As specified in df, each lower_ci and upper_ci should get the color in ci_color of the same row, which means each group may not get the same error bar color across questions. However, using the code below I get a strange result -- Group1 and Group2's error bars for Question B are swapped. How can I make sure the error bars correspond to the correct group and get the correct colors?

# Create a new data frame with group_name
df <- data.frame(
  question_name = c("A", "A", "A", "B", "B", "B"),
  group_name = c("Group1", "Group2", "Group3", "Group1", "Group2", "Group3"),
  estimate_weighted = c(20, 22, 24, 25, 28, 30),
  lower_ci = c(15, 20, 22, 22, 26, 28),
  upper_ci = c(25, 25, 26, 28, 30, 32),
  ci_color = c("black", "blue", "red", "blue", "black", "red")  # Set colors as intended
)

# Create the ggplot bar plot with grouped bars
ggplot(df, aes(x = factor(question_name), y = estimate_weighted, fill = factor(group_name))) +
  geom_bar(stat = "identity", position = position_dodge(0.9)) +
  geom_errorbar(
    aes(ymin = lower_ci, ymax = upper_ci, color = ci_color),
    width = 0.2,
    position = position_dodge(0.9)
  ) +
  scale_color_manual(values = c('black', 'blue', 'red')) +  # Specify colors explicitly
  labs(
    x = "Question Name",
    y = "Estimate Weighted",
    color = "CI Color"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

I tried changing the scale_color_manual to be exactly the same as ci_color, but still doesn't solve the problem.


Solution

  • The issue is that your error bars are implicitly grouped (and dodged) by color = ci_color whereas your bars are grouped by fill = factor(group_name). To align the error bars with the bars you have use the same grouping, which could be achieved by explicitly mapping on the the group aes, i.e. add group = factor(group_name) to geom_errorbar.

    Moreover, while the colors are assigned in the correct order in your example I would still suggest to use a named vector of colors to ensure that the right colors are assigned to the ci_color categories.

    library(ggplot2)
    
    pal_color <- c("black", "blue", "red")
    names(pal_color) <- pal_color
    pal_color
    #>   black    blue     red 
    #> "black"  "blue"   "red"
    
    ggplot(df, aes(
      x = factor(question_name),
      y = estimate_weighted,
      fill = factor(group_name)
    )) +
      geom_col(position = position_dodge(0.9)) +
      geom_errorbar(
        aes(
          ymin = lower_ci, ymax = upper_ci,
          color = ci_color, group = factor(group_name)
        ),
        width = 0.2,
        position = position_dodge(0.9)
      ) +
      scale_color_manual(values = pal_color) +
      labs(
        x = "Question Name",
        y = "Estimate Weighted",
        color = "CI Color"
      ) +
      theme_minimal() +
      theme(
        axis.text.x = element_text(angle = 45, hjust = 1)
      )