Cell-type distance to plaque — ridge plots

Distance distributions per annotated cell type, faceted by plaque type and treatment

Published

March 26, 2026

Setup and data loading

Code
source("R/setup.R")
library(ggridges)
library(patchwork)

data <- load_slides_and_distances("full")
slide1 <- data$slide1; slide2 <- data$slide2
cell_distances_1 <- data$distances_1; cell_distances_2 <- data$distances_2

message(sprintf("Cell types: %s",
  paste(sort(unique(slide1$annotatedclusters)), collapse = ", ")))
Code
# Join cell type and treatment from Seurat metadata
meta_lookup <- bind_rows(
  slide1@meta.data |> as_tibble(rownames = "cell") |>
    select(cell, annotatedclusters, Treatment.Group),
  slide2@meta.data |> as_tibble(rownames = "cell") |>
    select(cell, annotatedclusters, Treatment.Group)
)

# Pool distances and join metadata
cell_distances_all <- bind_rows(
  cell_distances_1 |> mutate(slide = 1L),
  cell_distances_2 |> mutate(slide = 2L)
) |>
  left_join(meta_lookup, by = "cell")

# Reshape to long format: one row per cell per plaque type
ridge_df <- cell_distances_all |>
  pivot_longer(cols = c(dist_caa, dist_paren),
               names_to = "plaque_type", values_to = "distance") |>
  mutate(
    plaque_type  = recode(plaque_type, dist_caa = "CAA", dist_paren = "Parenchymal"),
    distance_cap = pmin(distance, 500)
  )

# Cell counts per cell type
cell_distances_all |>
  count(annotatedclusters, Treatment.Group, name = "n_cells") |>
  pivot_wider(names_from = Treatment.Group, values_from = n_cells, values_fill = 0) |>
  mutate(total = Adu + IgG) |>
  arrange(desc(total)) |>
  kbl(caption = "Cell counts per annotated cluster and treatment") |>
  kable_styling("striped", full_width = FALSE)
Cell counts per annotated cluster and treatment
annotatedclusters Adu IgG total
Oligodendrocyte 36516 33808 70324
Astrocyte 25322 23167 48489
Glutamatergic Neuron 1 20693 18728 39421
Microglia 19614 15185 34799
Glutamatergic Neuron 2 16630 17705 34335
Endothelial 13324 12259 25583
GABAergic Neuron 1 10220 10955 21175
GABAergic Neuron 2 7529 7497 15026
NA 5138 6333 11471
OPC 5352 4526 9878
Glutamatergic Neuron 3 4239 3244 7483
Fibroblast 2916 3263 6179
Pericyte 3213 2714 5927
GABAergic Neuron 3 2585 2489 5074
Glutamatergic Neuron 4 2085 2070 4155
CP 1685 2444 4129
GABAergic Neuron 4 2008 2083 4091
Ependymal 1929 1675 3604
VSMC 1240 1296 2536
Glutamatergic Neuron 5 1092 902 1994
BAM 819 658 1477
VLMC 283 375 658
T Cell 392 199 591

Ridge plots — all cell types

Distance distributions for each cell type to the nearest CAA and parenchymal plaque, split by treatment group. Distances capped at 500 um for visualisation. The dashed line marks the 50 um proximity threshold.

Code
# Drop cells without annotation, then order by median distance to parenchymal plaques
ridge_df <- ridge_df |> filter(!is.na(annotatedclusters))

ct_order <- cell_distances_all |>
  filter(!is.na(annotatedclusters)) |>
  group_by(annotatedclusters) |>
  summarise(med_dist = median(dist_paren), .groups = "drop") |>
  arrange(med_dist) |>
  pull(annotatedclusters)

ridge_df <- ridge_df |>
  mutate(annotatedclusters = factor(annotatedclusters, levels = ct_order))

ggplot(ridge_df, aes(x = distance_cap, y = annotatedclusters, fill = Treatment.Group)) +
  geom_density_ridges(alpha = 0.5, scale = 1.2, rel_min_height = 0.01) +
  geom_vline(xintercept = 50, linetype = "dashed", colour = "grey30") +
  facet_wrap(~ plaque_type) +
  scale_fill_manual(values = c("IgG" = "#4DAF4A", "Adu" = "#E41A1C")) +
  labs(
    x = "Distance to nearest plaque (um, capped at 500)",
    y = NULL,
    fill = "Treatment"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    legend.position = "bottom",
    panel.grid.major.x = element_blank(),
    panel.grid.minor.x = element_blank(),
    strip.text = element_text(size = 14, face = "bold")
  )

Distance from each cell to its nearest plaque, stratified by annotated cell type and treatment. Faceted by plaque type (CAA vs Parenchymal).
Code
# Individual ridge plots per cell type for closer inspection
walk(ct_order, \(ct) {
  sub_df <- ridge_df |> filter(annotatedclusters == ct)
  if (nrow(sub_df) == 0) return(invisible(NULL))
  cat(sprintf("\n## %s\n\n", ct))

  p <- sub_df |>
    ggplot(aes(x = distance_cap, y = Treatment.Group, fill = Treatment.Group)) +
    geom_density_ridges(alpha = 0.6, scale = 1.2, rel_min_height = 0.01) +
    geom_vline(xintercept = 50, linetype = "dashed", colour = "grey30") +
    facet_wrap(~ plaque_type) +
    scale_fill_manual(values = c("IgG" = "#4DAF4A", "Adu" = "#E41A1C")) +
    labs(
      title = ct,
      x = "Distance to nearest plaque (um, capped at 500)",
      y = NULL,
      fill = "Treatment"
    ) +
    theme_minimal(base_size = 15) +
    theme(legend.position = "bottom",
    panel.grid = element_blank())

  print(p)
  cat("\n\n")
})

Microglia

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Glutamatergic Neuron 4

Per-cell-type ridge plots of distance to nearest plaque by treatment.

T Cell

Per-cell-type ridge plots of distance to nearest plaque by treatment.

VSMC

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Oligodendrocyte

Per-cell-type ridge plots of distance to nearest plaque by treatment.

OPC

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Pericyte

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Endothelial

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Astrocyte

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Glutamatergic Neuron 1

Per-cell-type ridge plots of distance to nearest plaque by treatment.

GABAergic Neuron 2

Per-cell-type ridge plots of distance to nearest plaque by treatment.

GABAergic Neuron 4

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Glutamatergic Neuron 3

Per-cell-type ridge plots of distance to nearest plaque by treatment.

BAM

Per-cell-type ridge plots of distance to nearest plaque by treatment.

GABAergic Neuron 3

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Glutamatergic Neuron 2

Per-cell-type ridge plots of distance to nearest plaque by treatment.

GABAergic Neuron 1

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Glutamatergic Neuron 5

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Fibroblast

Per-cell-type ridge plots of distance to nearest plaque by treatment.

Ependymal

Per-cell-type ridge plots of distance to nearest plaque by treatment.

VLMC

Per-cell-type ridge plots of distance to nearest plaque by treatment.

CP

Per-cell-type ridge plots of distance to nearest plaque by treatment.