5

I want to replace one of my grouped boxplots (below) to before-after kind, but keep it grouped. This one was made using ggboxplot() from ggpubr. I know there's also ggpaired() but I couldn't manage to make it grouped like this one.

grouped boxplot

Thanks to this question I was able to create grouped before-after graph like this one. I would now like to change the axis from 4 marks to just 2 (just "yes" and "no", since "before" and "after" are still in the legend. grouped dotplots with lines between them

Here's my code with dummy data:

library(tidyverse)

set.seed(123)
data.frame(ID = rep(LETTERS[1:10], 2),
           consent = rep(sample(c("Yes", "No"), 10, replace = T), 2),
           height = sample(rnorm(20, 170, sd = 10)),
           ind = rep(c("before", "after"), each = 2)
           ) %>%
  ggplot(aes(x = interaction(ind, consent), y = height, color = ind))+
  geom_point()+
  geom_line(aes(group = interaction(ID, consent)), color = "black")+
  scale_x_discrete("response")

Is it even possible to reduce number of categories on axis? Or can I create grouped plot using ggpaired(), but without using facets?

pogibas
  • 27,303
  • 19
  • 84
  • 117
Venca
  • 93
  • 1
  • 9

2 Answers2

2

Solution can be to create dummy numeric variable (in-between before and after) and put it on the x-axis. Then you can change it's names.

# Generate OP data
library(tidyverse)
set.seed(123)
df <- data.frame(ID = rep(LETTERS[1:10], 2),
           consent = rep(sample(c("Yes", "No"), 10, replace = T), 2),
           height = sample(rnorm(20, 170, sd = 10)),
           ind = rep(c("before", "after"), each = 2)
           )
df$name <- paste(df$consent, df$ind)

# Generate dummy numeric variable for `name` combinations 
foo <- data.frame(name = c("Yes before", "Yes", "Yes after", 
                           "No before", "No", "No after"),
                  X = 1:6)
#         name X
# 1 Yes before 1
# 2        Yes 2
# 3  Yes after 3
# 4  No before 4
# 5         No 5
# 6   No after 6

And now we just need to map name to X and put it on x-axis:

df <- merge(foo, df)
ggplot(df, aes(X, height))+
    geom_point(aes(color = ind)) +
    geom_line(aes(group = interaction(ID, consent))) +
    scale_x_continuous(breaks = c(2, 5), labels = foo$name[c(2, 5)])

enter image description here

pogibas
  • 27,303
  • 19
  • 84
  • 117
  • Thank you! This approach seems nice, didn't even cross my mind. I ended up using facets though, since I don't like to modify my dataframe and it's simpler when comparing groups with `stat_compare_means()` – Venca Apr 24 '18 at 08:18
  • @Venca yes, your facet solution also looks very neat! – pogibas Apr 24 '18 at 08:29
1

@camille made me think about facety solution. Apparently, it is possible to put facet labels not just to the bottom of the plot, but even under the axis. Which solved my problem without having to modify my dataframe:

library(ggpubr) #for theme_pubr and JCO palette

ggplot(df, aes(x = ind, y = height, group = ID))+
geom_point(aes(color = ind), size = 3)+
geom_line()+
labs(y = "Height")+
facet_wrap(~ consent, 
           strip.position = "bottom", ncol = 5)+   #put facet label to the bottom 
theme_pubr()+
color_palette("jco")+
theme(strip.placement = "outside",   #move the facet label under axis
      strip.text = element_text(size = 12),
      strip.background = element_blank(),
      axis.title.x = element_blank(),
      legend.position = "none")

Result with dataframe from the question:

Resulting image

Venca
  • 93
  • 1
  • 9