Check out the handy tips for connecting paired points in ggplots!
Feel so glad (and relieved) to blog again after three months of rest! This post was actually inspired by a recent project I am working on: I wanted to make a ggplot comparing the feeding response of control vs. treatment for each larval parent family on two plant types, and I would like to draw a line connecting the control-treatment pair for each family for each plant type. I thought it was a walk in the park, but when I started making the plot, it turned out to be more complicated than I imagined. Thankfully, after a bit of researching and experimenting, I figured it out and I felt it would be helpful to write something about it. So in this post, I’ll show you the tips for connecting paired points in ggplots. Let’s do it!
We will use the built-in CO2 dataset, which contains data from an experiment looking at how chilling affected the CO2 uptake rates of the grass species Echinochloa crus-galli.
Let’s start with the simplest case where we compare the CO2 uptake rates of the nonchilled vs. chilled plant individual #1 at different ambient CO2 concentrations. We’ll draw a line between each nonchilled-chilled pair to show the treatment effect.
library(tidyverse)
### Select plant individual #1
CO2_plant_1 <- filter(CO2, Plant %in% c("Qn1", "Qc1"))
### Plot
ggplot(CO2_plant_1) +
geom_point(aes(x = Treatment, y = uptake, shape = Treatment, color = factor(conc))) +
geom_line(aes(x = Treatment, y = uptake, color = factor(conc), group = factor(conc))) +
scale_color_brewer(palette = "Set1", name = "Ambient [CO2]") +
theme_classic(base_size = 13)
Looks like chilling reduces CO2 uptake rates of plant individual #1 under all ambient CO2 concentrations.
Now, what if we’re interested in other plant individuals? Would the patterns be similar? Let’s make another plot and see.
### Select plant individual #1 to #3
CO2_plant_1_to_3 <- filter(CO2, Plant %in% c("Qn1", "Qc1", "Qn2", "Qc2", "Qn3", "Qc3")) %>%
mutate(Plant_id = str_remove(Plant, "(n|c)")) %>%
mutate(Plant_conc_id = str_c(Plant_id, conc, sep = "_")) # create a unique id for the paired points
### Plot
ggplot(CO2_plant_1_to_3) +
geom_point(aes(x = Plant_id, y = uptake, group = Treatment, shape = Treatment, color = factor(conc)),
position = position_dodge(width = 0.8)) +
geom_line(aes(x = Plant_id, y = uptake, group = Plant_conc_id, color = factor(conc)),
position = position_dodge(width = 0.8)) +
scale_color_brewer(palette = "Set1", name = "Ambient [CO2]") +
theme_classic(base_size = 13)
Oops it doesn’t work. How can we solve this problem? Read below!
The first method is to create separate panels for each plant individual using facets. This is a easy quick fix.
### Plot
ggplot(CO2_plant_1_to_3) +
geom_point(aes(x = Treatment, y = uptake, color = factor(conc))) +
geom_line(aes(x = Treatment, y = uptake, group = factor(conc), color = factor(conc))) +
facet_wrap( ~ Plant_id) + # faceting by plant id
scale_color_brewer(palette = "Set1", name = "Ambient [CO2]") +
theme_classic(base_size = 13)
As we can see, all three plant individuals showed similar responses to chilling.
The second method is to manually dodge the endpoints of the connecting lines. This requires slightly more work, but is a non-facet alternative. So basically, we need to dodge the nonchilled and chilled points to the two sides of each plant individual (the x-positions of the three plants are indeed 1, 2, and 3), map the new dodged positions to the x aesthetic in geomline()
, and specify each plant individual–CO2 concentration combination as the grouping variable. Sounds a bit abstract?! Let’s take a look at the code below to get a better idea of how it works.
### Dodge the nonchilled and chilled points
CO2_plant_1_to_3_recoded <- CO2_plant_1_to_3 %>%
mutate(Plant_id_x = case_when(Plant_id == "Q1" ~ 1, # these are the x-positions of the three plant individuals
Plant_id == "Q2" ~ 2,
Plant_id == "Q3" ~ 3),
Plant_id_x_dodged = case_when(Treatment == "nonchilled" ~ Plant_id_x - 0.25, # dodge the "nonchilled" points to the left of each plant individual
Treatment == "chilled" ~ Plant_id_x + 0.25)) # dodge the "chilled" points to the right of each plant individual
### Plot
ggplot(CO2_plant_1_to_3_recoded) +
geom_point(aes(x = Plant_id, y = uptake, shape = Treatment, group = Treatment, color = factor(conc)),
position = position_dodge(width = 1)) +
geom_line(aes(x = Plant_id_x_dodged, y = uptake, group = Plant_conc_id, color = factor(conc))) +
scale_color_brewer(palette = "Set1", name = "Ambient [CO2]") +
theme_classic(base_size = 13)
We made it!
To recap, we looked at how to connect paired points with lines for a single group as well as for multiple groups. When there are multiple groups, we can use facets or manually dodge the endpoints of the lines. This type of paired-points plot is especially useful for visualizing the treatment effects, and I’m pretty sure you’ll be creating it in the future.
Hope you learn something useful from this post and don’t forget to leave your comments and suggestions below if you have any!
If you see mistakes or want to suggest changes, please create an issue on the source repository.