Representing paired pre/post data in an ordination with arrows using R and ggplot2 (CC428)

May 28, 2026 • PD Schloss • 1 min read

Pat refactors a difficult to interpret ordination diagram taken from a study that looked at the effects of acarbose and the microbiome on allergic responses. He highlights the importance of having a visualization that reflects the design of the study. This is done by replacing a scatter plot with a plot showing line segments that have arrow heads showing the direction of change of each animal in the study.

library(tidyverse)
library(readxl)

download.file("https://static-content.springer.com/esm/art%3A10.1038%2Fs41564-026-02350-2/MediaObjects/41564_2026_2350_MOESM6_ESM.xlsx",
              "fig_3.xlsx")

read_excel("fig_3.xlsx", sheet = "Fig. 3e", range = "C3:E67") %>%
  rename_all(tolower) %>%
  rename(treatment = sample) %>%
  mutate(time = rep(c("Before", "After"), each = 32),
         time = factor(time, levels = c("Before", "After")),
         replicate = paste(treatment, rep(1:8, times = 8)),
         treatment = factor(treatment,
                            levels = c("Ctrl", "Acr", "Abx", "Abx+Acr"))) %>%
  arrange(time) %>%
  ggplot(aes(x = pco1, y = pco2, color = treatment, shape = time,
             group = replicate)) +
  geom_path(linewidth = 0.4,
            arrow = arrow(type = "closed", length = unit(4, "pt"))) +
  scale_color_manual(
    values = c("Ctrl" = "#0700FE", "Acr" = "#FC0504", 
               "Abx" = "#FFA400", "Abx+Acr" = "#9D23EE"),
    labels = c("Ctrl" = "Control", "Acr" = "Acarbose", 
               "Abx" = "Antibiotics", "Abx+Acr" = "Antibiotics+\nAcarbose")
  ) +
  labs(
    x = "PCo 1 (47%)", y = "PCo 2 (22.8%)",
    color = NULL
  ) +
  theme_classic() +
  theme(
    axis.text = element_text(size = 6),
    axis.title = element_text(size = 7),
    axis.line = element_line(linewidth = 0.3),
    axis.ticks = element_line(linewidth = 0.3),
    legend.text = element_text(size = 6, margin = margin(l = 3),
                               lineheight = 0.7),
    legend.key.height = unit(9, "pt"),
    legend.key.width = unit(10, "pt"),
    legend.position = "inside",
    legend.position.inside = c(0.85, 0.85),
    legend.background = element_blank(),
    legend.key.justification = "top"
  )

ggsave("fig_3e.png", width = 2.5, height = 1.765)