# ── Summarize clade composition per location ───────────────────────────────────
# (when multiple samples share a location, show their clade proportions as a pie)
pie_data <- sample_data %>%
group_by(Longitude, Latitude, !!sym(CLADE_COL)) %>%
summarise(n = n(), .groups = "drop") %>%
tidyr::pivot_wider(names_from = all_of(CLADE_COL), values_from = n, values_fill = 0) %>%
mutate(radius = 0.4) # pie radius in degrees; adjust to your map scale
# ── Palette completion ────────────────────────────────────────────────────────
# Plotting only intersect(names(CLADE_COLORS), names(pie_data)) drops any clade
# the config forgot to list. The pies then still look correct while no longer
# representing the true sample composition. Instead: keep every clade in the
# data and give the unlisted ones fallback colours, loudly.
clades_present <- sort(unique(as.character(sample_data[[CLADE_COL]])))
clade_palette <- setNames(unname(CLADE_COLORS[clades_present]), clades_present)
missing_clades <- clades_present[is.na(clade_palette)]
if (length(missing_clades) > 0) {
clade_palette[missing_clades] <-
rep(CLADE_FALLBACK_COLORS, length.out = length(missing_clades))
message("Clades present in the data but absent from CLADE_COLORS (assigned ",
"fallback colours): ", paste(missing_clades, collapse = ", "))
}
unused_clades <- setdiff(names(CLADE_COLORS), clades_present)
if (length(unused_clades) > 0) {
message("CLADE_COLORS entries not present in the data (ignored): ",
paste(unused_clades, collapse = ", "))
}
pie_cols <- clades_present
stopifnot(all(pie_cols %in% names(pie_data)))
# Every sample must be represented by exactly one pie slice.
stopifnot(sum(as.matrix(pie_data[, pie_cols])) == nrow(sample_data))
# Country polygons
world <- ne_countries(scale = "medium", returnclass = "sf")
p_spie <- ggplot() +
geom_sf(data = world, fill = "grey90", color = "white", linewidth = 0.2) +
geom_scatterpie(
data = pie_data,
aes(x = Longitude, y = Latitude, r = radius),
cols = pie_cols,
alpha = 0.85, color = "black", linewidth = 0.2
) +
scale_fill_manual(values = clade_palette, name = "Clade") +
coord_sf(xlim = MAP_LON, ylim = MAP_LAT, expand = FALSE) +
annotation_scale(location = "br", width_hint = 0.25) +
labs(title = paste(PATHOGEN_NAME, "— Geographic Distribution"),
x = NULL, y = NULL) +
theme_bw(base_size = 9, base_family = "sans") +
theme(
legend.position = "top",
legend.direction = "horizontal",
legend.text = element_text(size = 6),
legend.key.size = unit(3, "pt"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_rect(color = "black", linewidth = 0.35),
axis.text = element_text(size = 8),
plot.margin = margin(4, 4, 4, 4, "pt")
)
ggsave(file.path(OUTPUT_DIR, "Maps", "scatter_pie.tiff"),
plot = p_spie, width = 3, height = 2, dpi = 600,
device = "tiff", compression = "lzw")
ggsave(file.path(OUTPUT_DIR, "Maps", "scatter_pie.svg"),
plot = p_spie, width = 3, height = 2, device = "svg")
print(p_spie)