Skip to content

Instantly share code, notes, and snippets.

@walkerke
Last active June 27, 2025 23:05
Show Gist options
  • Save walkerke/8b4230d3e1a098ed9f79ee9c62ac5e74 to your computer and use it in GitHub Desktop.
Save walkerke/8b4230d3e1a098ed9f79ee9c62ac5e74 to your computer and use it in GitHub Desktop.
library(tidyverse)
library(tidycensus)
# Get the data
pyramid_data <- get_estimates(
geography = "state",
product = "characteristics",
breakdown = c("AGEGROUP", "SEX"),
breakdown_labels = TRUE,
vintage = 2024,
year = 2024
) %>%
filter(AGEGROUP != "All ages", SEX != "Both sexes", NAME %in% c("Maine", "Utah")) %>%
group_by(NAME) %>%
mutate(
value_pct = value / sum(value) * 100,
value_pct = ifelse(SEX == "Male", -value_pct, value_pct)
) %>%
ungroup()
# Create enhanced population pyramids
ggplot(pyramid_data, aes(x = value_pct, y = AGEGROUP, fill = SEX)) +
geom_col(alpha = 0.9, width = 0.85) +
geom_vline(xintercept = 0, color = "gray40", linewidth = 0.5) +
scale_x_continuous(
labels = function(x) paste0(abs(x), "%"),
expand = expansion(mult = c(0.05, 0.05))
) +
scale_y_discrete(
labels = function(x) str_remove_all(x, "Age\\s|\\syears")
) +
scale_fill_manual(
values = c("Female" = "#A23B72", "Male" = "#2E86AB"),
breaks = c("Male", "Female") # This controls the legend order
) +
facet_wrap(~NAME, scales = "free_x") +
labs(
title = "The Oldest (Maine) and Youngest (Utah) States in the U.S.",
subtitle = "Population distribution by age and sex, 2024",
x = "Percentage of State Population",
y = "Age Group",
caption = "Source: U.S. Census Bureau, Vintage 2024 Population Estimates | tidycensus R package"
) +
theme_minimal(base_size = 11) +
theme(
# Title and text styling
plot.title = element_text(face = "bold", size = 18, hjust = 0.5,
margin = margin(b = 5)),
plot.subtitle = element_text(color = "gray50", size = 13, hjust = 0.5,
margin = margin(b = 15)),
plot.caption = element_text(color = "gray60", size = 9, hjust = 1,
margin = margin(t = 15)),
# Facet styling
strip.text = element_text(size = 14, face = "bold", color = "gray20"),
strip.background = element_rect(fill = "gray95", color = NA),
# Axis styling
axis.title.x = element_text(size = 11, margin = margin(t = 10)),
axis.title.y = element_text(size = 11, margin = margin(r = 10)),
axis.text.y = element_text(size = 10, color = "gray30"),
axis.text.x = element_text(size = 10, color = "gray30"),
# Grid styling
panel.grid.major.y = element_line(color = "gray90", linewidth = 0.3),
panel.grid.minor.y = element_blank(),
panel.grid.major.x = element_line(color = "gray85", linewidth = 0.3),
panel.grid.minor.x = element_blank(),
# Panel styling
panel.spacing = unit(1.5, "lines"),
# Legend styling - moved to bottom with horizontal layout
legend.position = "bottom",
legend.direction = "horizontal",
legend.title = element_text(size = 10, margin = margin(r = 3)), # Reduced spacing
legend.text = element_text(size = 10),
legend.key.width = unit(1.5, "cm"),
legend.key.height = unit(0.3, "cm"),
legend.margin = margin(t = 5, b = 0),
legend.spacing.x = unit(0.3, "cm"),
# Overall plot margins
plot.margin = margin(20, 20, 10, 20)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment