Shading bars conditionally in ggplot for multiple series bar charts

Viewed 127

I'm making bar charts that show the difference between groups over separate periods, however I also want to shade out certain bars that don't meet certain criteria (i.e CV > 20 or Sample_size < 30).

Can someone please help me to do this? I've attached a picture as an example of what I'm looking for my output to look like (mocked up in excel), and some example data below.

Thanks a million!!

Example data:

    structure(list(Group = c("A", "B", "C", "D", "E", "F", "G", "H", 
"I", "J", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J"), 
    Perc = c(38, 38, 46, 27, 18, 39, 43, 27, 38, 40, 39, 39, 
    50, 32, 33, 41, 52, 32, 43, 43), Lower_CI = c(36, 36, 36, 
    15, 8, 31, 30, 14, 18, 23, 38, 37, 40, 21, 15, 31, 40, 17, 
    24, 27), Upper_CI = c(39, 40, 57, 39, 27, 47, 55, 40, 58, 
    56, 41, 41, 60, 44, 51, 51, 64, 47, 63, 60), CV = c(2, 2, 
    11, 12, 28, 11, 15, 6, 18, 13, 2, 2, 10, 19, 5, 13, 12, 23, 
    14, 20), Sample_size = c(30, 15, 140, 40, 69, 75, 56, 256, 
    45, 536, 4852, 785, 36, 48, 315, 120, 83, 15, 123, 45), Period = c(1, 
    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)), row.names = c(NA, 
-20L), class = c("tbl_df", "tbl", "data.frame"))

Example of bar chart required

2 Answers

You can try a dplyr and ggplot2 pipeline. You can integrate a new value for Period using mutate(). After that you can also keep the same order for Group formating it as a factor. The plot you want is a dodged bar plot. Using ggplot2 functions you can reach that. Finally, move the axis using coord_flip(). The additional level created can be dropped using breaks inside scale_fill_manual(). Here the code:

library(ggplot2)
library(dplyr)
#Code
df %>%
  mutate(Period=ifelse(CV>20 | Sample_size<30,3,Period),
         Group=factor(Group,levels = rev(unique(Group)),ordered = T))%>%
  ggplot(aes(x=Group,y=Perc,fill=factor(Period)))+
  geom_bar(stat = 'identity',position = position_dodge(0.9))+
  geom_errorbar(aes(x=Group,ymin=Lower_CI,ymax=Upper_CI,group=Period),
                position = position_dodge(0.9))+
  scale_fill_manual(values=c('cornflowerblue','orange','gray'),
                    breaks=c('1','2'))+
  labs(fill='Period')+
  theme_bw()+
  coord_flip()

Output:

enter image description here

Some data used:

#Data
df <- structure(list(Group = c("A", "B", "C", "D", "E", "F", "G", "H", 
"I", "J", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J"), 
    Perc = c(38, 38, 46, 27, 18, 39, 43, 27, 38, 40, 39, 39, 
    50, 32, 33, 41, 52, 32, 43, 43), Lower_CI = c(36, 36, 36, 
    15, 8, 31, 30, 14, 18, 23, 38, 37, 40, 21, 15, 31, 40, 17, 
    24, 27), Upper_CI = c(39, 40, 57, 39, 27, 47, 55, 40, 58, 
    56, 41, 41, 60, 44, 51, 51, 64, 47, 63, 60), `(-)` = c(2, 
    2, 10, 12, 10, 8, 13, 13, 20, 17, 1, 2, 10, 11, 18, 10, 12, 
    15, 19, 16), `(+)` = c(1, 2, 11, 12, 9, 8, 12, 13, 20, 16, 
    2, 2, 10, 12, 18, 10, 12, 15, 20, 17), CV = c(2, 2, 11, 12, 
    28, 11, 15, 6, 18, 13, 2, 2, 10, 19, 5, 13, 12, 23, 14, 20
    ), Sample_size = c(30, 15, 140, 40, 69, 75, 56, 256, 45, 
    536, 4852, 785, 36, 48, 315, 120, 83, 15, 123, 45), Period = c(1, 
    1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)), row.names = c(NA, 
-20L), class = c("tbl_df", "tbl", "data.frame"))

You could do something like this:

library(ggplot2)

#create variable for color/fill 
df$col <- df$Period
df$col[df$Sample_size < 30 | df$CV > 20] = 3
df$col <- as.factor(df$col)

#plot
ggplot(data = df, aes(x = Group, y = Perc, group = Period, 
                      color = col, fill = col)) +
  geom_bar(stat = "identity", position = position_dodge()) +
  geom_errorbar(aes(ymin = Lower_CI, ymax = Upper_CI), 
                position = position_dodge())+
  scale_color_manual(values = c("blue", "orange", "grey"), 
                     breaks = c("1", "2"),) +
  scale_fill_manual(values = c("blue", "orange", "grey"), 
                    breaks = c("1", "2")) +
  coord_flip()+
  theme_bw() + theme(legend.title = element_blank())

enter image description here

Related