Search code examples
rggplot2jittergroup

Plot a ggplot geom_boxplot with geom_jitter, separated by a factor and showing only box median


I have a data.frame with two factor variables (type and age in df below) and a single numeric variable (value in df below):

set.seed(1)
df <- data.frame(type = c(rep("t1", 8), rep("t2", 8), rep("t3", 8), rep("t4", 8), rep("t5", 8), rep("t6", 8)),
                 age = rep(c(rep("y", 4),rep("o", 4)), 6),
                 value = rep(c(runif(4, 5, 10), runif(4, 7.5, 12.5)), 6),
                 stringsAsFactors = F)
df$type <- factor(df$type, levels = c("t1", "t2", "t3", "t4", "t5", "t6"), ordered = T)
df$age <- factor(df$age, levels = c("y", "o"), ordered = T)

I want to use R's ggplot2 to plot df$value as jittered points, grouped and color-coded by df$type, but within df$type separated by df$age. In addition, I want to show the median line for each group of df$type and df$age.

So far I can only get the points plotted without the median lines:

library(ggplot2)
ggplot(df, aes(x = age, y = value, color = type)) + 
  geom_jitter(width = 0.3) +
  facet_wrap(~type,nrow = 1) + theme_minimal()

enter image description here

Any idea how to add the median lines?


Solution

  • Your example data was the same for all types, so I changed it a bit:

    set.seed(1)
    df <- data.frame(type = c(rep("t1", 8), rep("t2", 8), rep("t3", 8), rep("t4", 8), rep("t5", 8), rep("t6", 8)),
                     age = rep(c(rep("y", 4),rep("o", 4)), 6),
                     value = runif(48, 5, 10),
                     stringsAsFactors = F)
    df$type <- factor(df$type, levels = c("t1", "t2", "t3", "t4", "t5", "t6"), ordered = T)
    df$age <- factor(df$age, levels = c("y", "o"), ordered = T)
    

    You can use stat_summary for this:

    ggplot(df) + 
      geom_jitter(aes(x = age, 
                      y = value,
                      color = type,
                      group = age),
                  width = 0.2) +
      
      stat_summary(aes(x = age,
                       y = value,
                       color = type,
                       group = interaction(age, type)), 
                   fun = median,
                   geom = "crossbar") +
      
      scale_color_brewer(palette = "Dark2") +
      
      facet_wrap(~type,nrow = 1) + 
      
      theme_bw()
    

    enter image description here