Ginko-Mitten
Ginko-Mitten

Reputation: 390

How to add error-bars to a grouped stacked barplot in R which requires reversing of levels?

I'm trying to create a stacked barplot with errorbars. The datafile is here: https://github.com/Ginko-Mitten/Experimental.git

library(ggplot2)
Dat1<-Methods_Recovery_Comparison
Volunteer<-as.factor(Dat1$Volunteer)
Method<-as.factor(Dat1$Method)
Phase<-as.factor(Dat1$Phase)
Recovery<-as.numeric(Dat1$Recovery)
SD<-as.numeric(Dat1$SD)
SDU<-Recovery+SD
SDL<-Recovery-SD
Ext<-data.frame(Volunteer,Method,Phase,Recovery,SD,SDU,SDL)

ggplot(Ext,aes(Method))+
  geom_bar(aes(weight = Recovery, fill = Phase))+
  facet_grid(~Volunteer)+
  geom_errorbar(aes(ymax=Recovery+SD,ymin=Recovery-SD))

The Plot I'm getting now

I would really like:
1. The order of the Phase to be reversed
2. The error-bars to align properly to the bars

Edit: Additional Request: Would it be possible to specifically lighten or make the bar hollow for value of Volunteer 3-> Method 2 -> Phase 3? (The corresponding recovery value is 10.5). That particular value was an anomalous one and would like to highlight it in the description while writing up.

Upvotes: 1

Views: 1792

Answers (2)

miach
miach

Reputation: 1

I had the same problem and thanks for the nice answer above, it works nicely for positive only data. In my case the y values are sometimes also negative, which makes the stack a little bit more complicated: it stacks the columns below and above 0. The same has also to happen with the positions for the error bars, which means the positive and the negative values have to be stacked (values cumulated) separately.

A little function can do the job:

    library(base)
    stack_pos <- function(vector){
    a <- as.vector(vector, mode= "numeric")
    b <- a > 0   
    a[b] <- rev(cumsum(rev(a[b])))
    a[!b] <- rev(cumsum(rev(a[!b])))
        a}

and can be put into the dplyr mutation in the answer above:

    library(dplyr)
    DF <- df %>% group_by(Volunteer, Method) %>% 
    mutate(SDpos = stack_pos(Recovery))

Note: because of the the double rev() in the stack_pos function the order of levels(DF$Phase) does not have to be changed anymore.

Upvotes: 0

dc37
dc37

Reputation: 16178

The creator of ggplot2 is not a big fan of error bars on stacked barchart (see: https://github.com/tidyverse/ggplot2/issues/1079) so there is no convenient way implemented in ggplot2 to do that.

The trick is to calculate the y position of the error bar in the stack. Here I used dplyr to create new column in function of Volunteer and Method that will cumulative add Recovery in order to get the y position for each error bar:

library(dplyr)
DF <- df %>% group_by(Volunteer, Method) %>% 
  mutate(Phase = factor(Phase, levels = c("Part3","Part2","Part1"))) %>%
  mutate(SDpos = cumsum(Recovery))

# A tibble: 27 x 6
# Groups:   Volunteer, Method [9]
   Volunteer Method  Phase Recovery    SD SDpos
   <chr>     <chr>   <fct>    <dbl> <dbl> <dbl>
 1 P1        Method1 Part1     50.6   0.1  50.6
 2 P1        Method1 Part2     15.4   1.2  66  
 3 P1        Method1 Part3      8.8   2.1  74.8
 4 P1        Method2 Part1     50.6   0.1  50.6
 5 P1        Method2 Part2     15.4   1.2  66  
 6 P1        Method2 Part3     14.6   2.9  80.6
 7 P1        Method3 Part1     50.6   0.1  50.6
 8 P1        Method3 Part2     14.6   1.9  65.2
 9 P1        Method3 Part3     16.6   2.3  81.8
10 P2        Method1 Part1     25.8   0.1  25.8
# … with 17 more rows

Then, I will make the stacked bargraph and add geom_errorbar based on the SDpos column I made (it will be my y values):

library(ggplot2)
ggplot(DF, aes(x = Method, y = Recovery, fill = Phase))+
  geom_col()+
  facet_wrap(.~Volunteer) +
  scale_fill_discrete(breaks = c("Part1","Part2","Part3"))+
  geom_errorbar(aes(ymin = SDpos-SD, ymax = SDpos+SD), width = 0.2)

enter image description here

Does it look what you are trying to get ?

Upvotes: 2

Related Questions