How to plot a hybrid boxplot: half boxplot with jitter points on the other half?

前端 未结 3 512
梦谈多话
梦谈多话 2020-11-28 10:35

I\'m trying to make a similar plot to Fig. 2d-f in an article published on Nature this year. It\'s basically a half boxplot with points on the other half.

Can anyone

3条回答
  •  一整个雨季
    2020-11-28 11:20

    A very fast solution would be to add some nudge using position_nudge.

    dat_long %>% 
     ggplot(aes(x = type, y = value, fill=key)) +
      geom_boxplot(outlier.color = NA) +
      geom_point(position = position_nudge(x=0.5), shape = 21, size = 2) + 
      facet_grid(loc ~ key)
    

    Or transform the x axis factor to numeric and add some value

    dat_long %>% 
     ggplot(aes(x = type, y = value, fill=key)) +
      geom_boxplot(outlier.color = NA) +
      geom_point(aes(as.numeric(type) + 0.5), shape = 21, size = 2) + 
      facet_grid(loc ~ key)
    

    A more generalised method regarding the x axis position would be following. In brief, the idea is to add a second data layer of the same boxes. The second boxes are hided using suitable linetype and alpha (see scale_) but could be easily overplotted by the points.

    dat_long <- dat %>%  
      gather(key, value, 1:6) %>% 
      mutate(loc = factor(loc, levels = c("abro", "dome")),
             type = factor(type),
             key = factor(key)) %>% 
      mutate(gr=1) # adding factor level for first layer
    
    dat_long %>% 
      mutate(gr=2) %>% # adding factor level for second invisible layer
      bind_rows(dat_long) %>% # add the same data
     ggplot(aes(x = type, y = value, fill=key, alpha=factor(gr), linetype = factor(gr))) +
      geom_boxplot(outlier.color = NA) +
      facet_grid(loc ~ key) + 
      geom_point(data=. %>% filter(gr==1),position = position_nudge(y=0,x=0.2), shape = 21, size = 2)+
      scale_alpha_discrete(range = c(1, 0)) +
      scale_linetype_manual(values = c("solid","blank")) +
      guides(alpha ="none", linetype="none")
    

    Using the code zankuralt posted below and optimise it for faceting you can try:

    dat %>% 
      gather(key, value, 1:6) %>% 
      mutate(loc = factor(loc, levels = c("abro", "dome")),
             type = factor(type),
             key = factor(key)) %>% 
      mutate(type2=as.numeric(type)) %>% 
      group_by(type, loc, key) %>%
      mutate(d_ymin = min(value),
             d_ymax = max(value),
             d_lower = quantile(value, 0.25),
             d_middle = median(value),
             d_upper = quantile(value, 0.75)) %>% 
      ggplot() +
      geom_boxplot(aes(x = type2 - 0.2,
                        ymin = d_lower,
                        ymax = d_upper,
                        lower = d_lower,
                        middle = d_middle,
                        upper = d_upper,
                        width = 2 * 0.2,
                        fill = key),
                   stat = "identity") +
      geom_jitter(aes(x = type2 + 0.2,
                       y = value,
                       color = key),
                  width = 0.2 - 0.25 * 0.2,
                  height = 0)+
    
      # vertical segment
      geom_segment(aes(x = type2,
                       y = d_ymin,
                       xend = type2,
                       yend = d_ymax)) +
    
      # top horizontal segment
      geom_segment(aes(x = type2 - 0.1,
                       y = d_ymax,
                       xend = type2,
                       yend = d_ymax)) +
    
      # top vertical segment
      geom_segment(aes(x = type2 - 0.1,
                       y = d_ymin,
                       xend = type2,
                       yend = d_ymin)) +
    
      # have to manually add in the x scale because we made everything numeric
      # to do the shifting
      scale_x_continuous(breaks = c(1,2),
                         labels = c("big","small"))+
       facet_grid(loc ~ key)
    

提交回复
热议问题