Connecting ggplot2::geom_point() with ggplot2::geom_line() in repeated measures

Viewed 198

I would like to connect the dots in my plot based on id. The problem is that on my x-axis I am positioning the geom_point() with position_dodge(), so I am not quite sure how I should map this.

Reprex:

library(ggplot2)

df <- structure(list(id = c("id24", "id24", "id27", "id27", "id29", 
                            "id29", "id34", "id34", "id35", "id35", "id44", "id44", "id01", 
                            "id01", "id03", "id03", "id04", "id04"), phase = c("time1", "time2", 
                                                                               "time1", "time2", "time1", "time2", "time1", "time2", "time1", 
                                                                               "time2", "time1", "time2", "time1", "time2", "time1", "time2", 
                                                                               "time1", "time2"), value = c(3.72638957446809, 3.92324338297872, 
                                                                                                            3.7271745106383, 3.79455578723404, 3.96383646808511, 4.28965153829787, 
                                                                                                            4.44174112765957, 4.80494985106383, 4.11124778723404, 4.39377629787234, 
                                                                                                            2.91550910638298, 3.21677434042553, 3.4524314893617, 4.2533229787234, 
                                                                                                            3.07149085106383, 3.38445914893617, 3.8882985106383, 4.78346468085106
                                                                               ), group = c("group1", "group1", "group1", "group1", "group1", 
                                                                                            "group1", "group2", "group2", "group2", "group2", "group2", "group2", 
                                                                                            "group3", "group3", "group3", "group3", "group3", "group3")), row.names = c(NA, 
                                                                                                                                                                        -18L), class = c("tbl_df", "tbl", "data.frame"))

ggplot(df, aes(group, value)) +
  geom_point(aes(group = phase),  position = position_dodge(width = 0.5)) +
  theme_light()

Created on 2020-07-08 by the reprex package (v0.3.0)


I know that this would have been the most straighforward way of doing this:

ggplot(df, aes(phase, value)) +
  geom_point(position = position_dodge(width = 0.5)) +
  geom_line(aes(group = id)) +
  theme_light()

Created on 2020-07-08 by the reprex package (v0.3.0)

But I need to have group in the x-axis, which is then positioned by phase. Any ideas?

1 Answers

It sounds like what you are looking for is essentially a nested categorical x axis. This is what faceting is for in ggplot, but isn't quite the look you are aiming for. However, you can set various theme elements to hide the fact that you are faceting. I think this is easier than the alternative, which is pivoting your data on phase and drawing geom_segments for each id, but this also requires a bit of spoofing of the categorical x axis, and gives essentially identical results:

ggplot(df, aes(phase, value)) +
  geom_point(aes(color = id)) +
  geom_vline(aes(xintercept = c(1.5)), colour = "gray85") +
  geom_vline(aes(xintercept = c(0.5)), colour = "gray85") +
  geom_line(aes(group = id, color = id)) +
  coord_cartesian(xlim = c(0.5, 2.5), ylim = c(2.49, 5), expand = 0) +
  theme_light() +
  labs(x = "group") +
  facet_wrap(.~group, strip.position = "bottom") +
  theme(strip.placement = "outside",
        axis.text.x = element_blank(),
        strip.text.x = element_text(colour = "black"),
        strip.background = element_rect(fill = "white"),
        panel.spacing.x = unit(0, "npc"),
        panel.border = element_rect(fill = NA, colour = NA),
        panel.grid.major.x = element_blank())

enter image description here

Without faceting:

df %>% 
  pivot_wider(names_from = "phase") %>% 
  mutate(group = as.factor(group)) %>%
  mutate(x0 = as.numeric(group) - 0.25, xend = as.numeric(group) + 0.25) %>%
  ggplot(aes(x = group, colour = id)) +
  geom_point(aes(x = x0, y = time1)) +
  geom_point(aes(x = xend, y = time2)) +
  geom_segment(aes(x = x0, y = time1, xend = xend, yend = time2)) +
  scale_x_continuous(breaks = 1:3, labels = levels(as.factor(df$group))) +
  theme_light()

enter image description here

Related