Search code examples
rggplot2boxplot

fill a boxplot with two colors based on value in ggplot


I have the data :


    dput(SO1)
    structure(list(country_n = c("Austria", "Belgium", "Czechia", 
    "Denmark", "Finland", "France", "Germany", "Hungary", "Ireland", 
    "Italy", "Latvia", "Netherlands", "Romania", "Spain", "Sweden", 
    "Austria", "Belgium", "Czechia", "Denmark", "Finland", "France", 
    "Germany", "Hungary", "Ireland", "Italy", "Latvia", "Netherlands", 
    "Romania", "Spain", "Sweden", "Austria", "Belgium", "Czechia", 
    "Denmark", "Finland", "France", "Germany", "Hungary", "Ireland", 
    "Italy", "Latvia", "Netherlands", "Romania", "Spain", "Sweden", 
    "Austria", "Belgium", "Czechia", "Denmark", "Finland", "France", 
    "Germany", "Hungary", "Ireland", "Italy", "Latvia", "Netherlands", 
    "Romania", "Spain", "Sweden"), org = c("MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", "MAG", 
    "MAG", "MAG"), P99_9s = c(1.24, 1.13, 0.887, 1.36, 2.07, 1.46, 
    1.24, 1.1, 0.832, 1.85, 1.07, 1.33, 1.91, 2.33, 1.29, 0.407, 
    0.367, 0.268, 0.415, 0.491, 0.397, 0.432, 0.339, 0.364, 0.464, 
    0.46, 0.417, 0.602, 0.53, 0.443, 0.327, 0.311, 0.227, 0.284, 
    0.331, 0.348, 0.362, 0.306, 0.313, 0.397, 0.289, 0.337, 0.417, 
    0.433, 0.285, 0.323, 0.304, 0.223, 0.278, 0.322, 0.344, 0.363, 
    0.303, 0.303, 0.409, 0.281, 0.329, 0.413, 0.439, 0.285)), class = "data.frame", row.names = c(NA, 
    -60L))

and want to make a boxplot that shows the values below and above P99_9s=1 by filling the same box with two different colors. I have got to the point

colors = c( "lightgreen","#1565c0")
mcolors <- ifelse(SO1$P99_9s>1,colors[1],colors[2])
 
 pSO <-  ggplot(SO1 , aes(x=reorder(org,P99_9s),  y=P99_9s , fill=mcolors, colour=mcolors) )   + 
   geom_boxplot(stat='boxplot', alpha=0.8) + coord_flip()+
   geom_hline(yintercept =1, col='red')+ scale_fill_identity()+scale_colour_identity()

which gets close, but splits the box into two parts (upper part of figure), while I would like to keep together (bottom of the figure, which I drew by hand).

the upper part is done with ggplot, the bottom part I drew to show the desired output

any suggestion?


Solution

  • at the end the easiest was to color-code the boxes to the threshold value. I added one more layer to group properly:

    SO$mcolors <- as.factor(ifelse(SO$P99_9s>1,'P','NP'))
     SO <- SO %>% group_by(org, effect) %>% mutate(Pr=ifelse('P' %in% mcolors,colors[1],colors[2]))
    

    and then the plot:

    pSO <-  ggplot(SO , aes(x=reorder(org,P99_9s),  y=P99_9s , fill=Pr, colour=Pr))   + 
       geom_boxplot(stat='boxplot', alpha=0.7) + coord_flip()+ 
      
       geom_hline(yintercept =1, col='red')  + theme_classic()   + 
       scale_fill_identity()+scale_colour_identity()
    

    which assigns color to the boxes if any of the value is above 1.