Skip to content

Instantly share code, notes, and snippets.

@ryanburge
Created November 2, 2025 14:24
Show Gist options
  • Select an option

  • Save ryanburge/2bf701a180c866b547aef226a91a6cde to your computer and use it in GitHub Desktop.

Select an option

Save ryanburge/2bf701a180c866b547aef226a91a6cde to your computer and use it in GitHub Desktop.
# helper to avoid repeating yourself
make_reltrad_by_year <- function(dat, wt_col) {
dat %>%
gss_reltrad6(reltrad) %>%
group_by(year) %>%
ct(reltrad, wt = {{ wt_col }})
}
# 1972–2002 → WTSSPS
gg_pre2004 <- gss %>%
filter(year <= 2002) %>%
make_reltrad_by_year(wtssps)
# 2004–2024 → WTSSNRPS (preferred where available)
gg_2004_2024 <- gss %>%
filter(year >= 2004, year <= 2024) %>%
make_reltrad_by_year(wtssnrps)
# bind + tidy
gg_all <- bind_rows(gg_pre2004, gg_2004_2024) %>%
arrange(year, reltrad)
graph <- gg_all %>% filter(reltrad != "NA")
graph %>%
ggplot(., aes(x = year, y = pct, color = reltrad, group = reltrad)) +
geom_line() +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb() +
scale_color_manual(
values = c(
"Evangelical" = "#FF4E00", # vivid orange
"Mainline" = "#0077FF", # bright blue
"Catholic" = "#22CC22", # bright green
"Black Prot." = "#A500FF", # electric purple
"No Religion" = "#FF006E", # hot pink/red
"Other Faith" = "#FFD700" # gold
)
) +
scale_y_continuous(labels = percent, limits = c(0, .32)) +
add_text(x = 2002, y = .29, word = "Catholic", sz = 8) +
add_text(x = 2002, y = .22, word = "Evangelical", sz = 8) +
add_text(x = 1985, y = .175, word = "Mainline", sz = 8) +
add_text(x = 2021, y = .30, word = "Nones", sz = 8) +
add_text(x = 2002, y = .04, word = "Black Prot.", sz = 8) +
add_text(x = 2023, y = .13, word = "Other", sz = 8) +
labs(x = "Year", y = "", title = "The American Religious Landscape, 1972-2024", caption = "@ryanburge | Data: General Social Survey, 1972-2024")
save("gss_reltrad6_2024.png")
graph %>%
filter(reltrad == "Evangelical") %>%
ggplot(., aes(x = year, y = pct, color = reltrad, group = reltrad)) +
geom_line() +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb() +
scale_color_manual(
values = c(
"Evangelical" = "#FF4E00", # vivid orange
"Mainline" = "#0077FF", # bright blue
"Catholic" = "#22CC22", # bright green
"Black Prot." = "#A500FF", # electric purple
"No Religion" = "#FF006E", # hot pink/red
"Other Faith" = "#FFD700" # gold
)
) +
scale_y_continuous(labels = percent, limits = c(0, .32)) +
add_text(x = 1972, y = .167, word = "18%", sz = 8) +
add_text(x = 1991, y = .305, word = "29%", sz = 8) +
add_text(x = 2012, y = .260, word = "25%", sz = 8) +
add_text(x = 2021, y = .150, word = "17%", sz = 8) +
add_text(x = 2024, y = .210, word = "19.5%", sz = 8) +
theme(plot.title = element_text(size = 22)) +
labs(x = "Year", y = "", title = "American Evangelicals, 1972-2024", caption = "@ryanburge | Data: General Social Survey, 1972-2024")
save("gss_evangelicals_2024.png")
graph %>%
filter(reltrad == "Mainline") %>%
ggplot(., aes(x = year, y = pct, color = reltrad, group = reltrad)) +
geom_line() +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb() +
scale_color_manual(
values = c(
"Evangelical" = "#FF4E00", # vivid orange
"Mainline" = "#0077FF", # bright blue
"Catholic" = "#22CC22", # bright green
"Black Prot." = "#A500FF", # electric purple
"No Religion" = "#FF006E", # hot pink/red
"Other Faith" = "#FFD700" # gold
)
) +
scale_y_continuous(labels = percent, limits = c(0, .32)) +
add_text(x = 1975, y = .315, word = "30%", sz = 8) +
add_text(x = 1986, y = .178, word = "19%", sz = 8) +
add_text(x = 2004, y = .110, word = "12%", sz = 8) +
add_text(x = 2016, y = .085, word = "10%", sz = 8) +
add_text(x = 2024, y = .070, word = "8.7%", sz = 8) +
theme(plot.title = element_text(size = 22)) +
labs(x = "Year", y = "", title = "American Mainline Protestants, 1972-2024", caption = "@ryanburge | Data: General Social Survey, 1972-2024")
save("gss_mainline_2024.png")
graph %>%
filter(reltrad == "Catholic") %>%
ggplot(., aes(x = year, y = pct, color = reltrad, group = reltrad)) +
geom_line() +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb() +
scale_color_manual(
values = c(
"Evangelical" = "#FF4E00", # vivid orange
"Mainline" = "#0077FF", # bright blue
"Catholic" = "#22CC22", # bright green
"Black Prot." = "#A500FF", # electric purple
"No Religion" = "#FF006E", # hot pink/red
"Other Faith" = "#FFD700" # gold
)
) +
scale_y_continuous(labels = percent, limits = c(0, .32)) +
add_text(x = 1976, y = .2875, word = "27%", sz = 8) +
add_text(x = 1994, y = .298, word = "28%", sz = 8) +
add_text(x = 2010, y = .285, word = "27%", sz = 8) +
add_text(x = 2024, y = .200, word = "22%", sz = 8) +
theme(plot.title = element_text(size = 22)) +
labs(x = "Year", y = "", title = "American Catholics, 1972-2024", caption = "@ryanburge | Data: General Social Survey, 1972-2024")
save("gss_catholics_2024.png")
graph %>%
filter(reltrad == "Black Prot.") %>%
ggplot(., aes(x = year, y = pct, color = reltrad, group = reltrad)) +
geom_line() +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb() +
scale_color_manual(
values = c(
"Evangelical" = "#FF4E00", # vivid orange
"Mainline" = "#0077FF", # bright blue
"Catholic" = "#22CC22", # bright green
"Black Prot." = "#A500FF", # electric purple
"No Religion" = "#FF006E", # hot pink/red
"Other Faith" = "#FFD700" # gold
)
) +
scale_y_continuous(labels = percent, limits = c(0, .32)) +
add_text(x = 1972, y = .105, word = "9%", sz = 8) +
add_text(x = 1988, y = .0525, word = "7%", sz = 8) +
add_text(x = 2016, y = .0355, word = "5%", sz = 8) +
add_text(x = 2024, y = .0305, word = "4.4%", sz = 8) +
theme(plot.title = element_text(size = 22)) +
labs(x = "Year", y = "", title = "American Black Protestants, 1972-2024", caption = "@ryanburge | Data: General Social Survey, 1972-2024")
save("gss_black_prot_2024.png")
graph %>%
filter(reltrad == "No Religion") %>%
ggplot(., aes(x = year, y = pct, color = reltrad, group = reltrad)) +
geom_line() +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb() +
scale_color_manual(
values = c(
"Evangelical" = "#FF4E00", # vivid orange
"Mainline" = "#0077FF", # bright blue
"Catholic" = "#22CC22", # bright green
"Black Prot." = "#A500FF", # electric purple
"No Religion" = "#FF006E", # hot pink/red
"Other Faith" = "#FFD700" # gold
)
) +
scale_y_continuous(labels = percent, limits = c(0, .32)) +
add_text(x = 1972, y = .040, word = "5.5%", sz = 8) +
add_text(x = 1991, y = .05, word = "6.7%", sz = 8) +
add_text(x = 2006, y = .180, word = "16%", sz = 8) +
add_text(x = 2021, y = .30, word = "28%", sz = 8) +
add_text(x = 2024, y = .2375, word = "25.2%", sz = 8) +
theme(plot.title = element_text(size = 22)) +
labs(x = "Year", y = "", title = "Americans With No Religious Affiliation, 1972-2024", caption = "@ryanburge | Data: General Social Survey, 1972-2024")
save("gss_nones_2024.png")
# --- 1) Define generations from birth cohort ---
# GSS has COHORT = birth year. If missing, fall back to year - age.
gss_gen <- gss %>%
mutate(
cohort_by = ifelse(!is.na(cohort), cohort, year - age),
gen = frcode(
cohort_by >= 1928 & cohort_by <= 1945 ~ "Silent",
cohort_by >= 1946 & cohort_by <= 1964 ~ "Boomer",
cohort_by >= 1965 & cohort_by <= 1980 ~ "Gen X",
cohort_by >= 1981 & cohort_by <= 1996 ~ "Millennial",
cohort_by >= 1997 & cohort_by <= 2012 ~ "Gen Z",
TRUE ~ NA_character_
)
)
# --- 2) Helper to reduce repetition (same as before) ---
make_by_year <- function(dat, var, wt_col) {
dat %>%
group_by(year) %>%
ct({{ var }}, wt = {{ wt_col }})
}
# --- 3) Weights by era (same rule as reltrad) ---
gg_gen_pre2004 <- gss_gen %>%
filter(year <= 2002) %>%
make_by_year(gen, wtssps)
gg_gen_2004_2024 <- gss_gen %>%
filter(year >= 2004, year <= 2024) %>%
make_by_year(gen, wtssnrps)
# --- 4) Bind and clean ---
gen_graph <- bind_rows(gg_gen_pre2004, gg_gen_2004_2024) %>%
filter(gen != "NA") %>%
arrange(year, gen)
# --- 5) Bright, high-contrast palette ---
gen_pal <- c(
"Silent" = "#A500FF", # electric purple
"Boomer" = "#0077FF", # bright blue
"Gen X" = "#22CC22", # bright green
"Millennial" = "#FF4E00", # vivid orange
"Gen Z" = "#FF006E" # hot pink/red
)
# --- 6) Main generations time series plot ---
gen_graph %>%
ggplot(aes(x = year, y = pct, color = gen, group = gen)) +
geom_line(linewidth = 1.2) +
geom_point(stroke = 1, shape = 21, fill = "white") +
theme_rb(legend = TRUE) +
scale_color_manual(values = gen_pal) +
scale_y_continuous(labels = scales::percent, limits = c(0, .40)) +
labs(
x = "Year", y = "",
title = "Generational Composition of U.S. Adults, 1972–2024",
caption = "@ryanburge | Data: General Social Survey, 1972–2024"
)
save("gss_generations_1972_2024.png")
# --- 0) Palettes + helpers ---
gen_pal <- c(
"Silent" = "#A500FF",
"Boomer" = "#0077FF",
"Gen X" = "#22CC22",
"Millennial" = "#FF4E00",
"Gen Z" = "#FF006E"
)
# --- 1) Build generations + reltrad; make nonreligious flag ---
gss_gen_rel <- gss %>%
# COHORT is birth year in GSS; if missing, derive as year - age
mutate(
cohort_by = ifelse(!is.na(cohort), cohort, year - age),
gen = frcode(
cohort_by >= 1928 & cohort_by <= 1945 ~ "Silent",
cohort_by >= 1946 & cohort_by <= 1964 ~ "Boomer",
cohort_by >= 1965 & cohort_by <= 1980 ~ "Gen X",
cohort_by >= 1981 & cohort_by <= 1996 ~ "Millennial",
cohort_by >= 1997 & cohort_by <= 2012 ~ "Gen Z"
)
) %>%
gss_reltrad6(reltrad) %>%
mutate(nones = frcode(reltrad == "No Religion" ~ "Non-religious",
reltrad != "No Religion" ~ "Religious"))
# --- 2) Helper to compute % nones by year x gen with a given weight ---
pct_nones <- function(dat, wt_col) {
dat %>%
filter(!is.na(gen)) %>%
group_by(year, gen) %>%
ct(nones, wt = {{ wt_col }}) %>%
filter(nones == "Non-religious") %>%
select(year, gen, pct)
}
# --- 3) Apply weights by era and bind ---
gen_nones_pre2004 <- gss_gen_rel %>%
filter(year <= 2002) %>%
pct_nones(wtssps)
gen_nones_2004_2024 <- gss_gen_rel %>%
filter(year >= 2004, year <= 2024) %>%
pct_nones(wtssnrps)
gen_nones <- bind_rows(gen_nones_pre2004, gen_nones_2004_2024) %>%
arrange(year, gen)
# --- 4) Plot: one time series with a line per generation ---
gen_nones %>%
ggplot(aes(x = year, y = pct, color = gen, group = gen)) +
geom_line(linewidth = 1.2) +
geom_point(shape = 21, stroke = 1, fill = "white") +
theme_rb() +
scale_color_manual(values = gen_pal) +
scale_y_continuous(labels = scales::percent, limits = c(0, 0.60)) +
labs(
x = "Year", y = "",
title = "Share Non-Religious by Generation, 1972–2024",
caption = "@ryanburge | Data: General Social Survey, 1972–2024"
)
save("gss_nones_by_generation_1972_2024.png")
# 1) Build generations + nones flag
gss_gen_rel <- gss %>%
mutate(
cohort_by = ifelse(!is.na(cohort), cohort, year - age),
gen = frcode(
cohort_by >= 1928 & cohort_by <= 1945 ~ "Silent",
cohort_by >= 1946 & cohort_by <= 1964 ~ "Boomer",
cohort_by >= 1965 & cohort_by <= 1980 ~ "Gen X",
cohort_by >= 1981 & cohort_by <= 1996 ~ "Millennial",
cohort_by >= 1997 & cohort_by <= 2012 ~ "Gen Z"
)
) %>%
gss_reltrad6(reltrad) %>%
mutate(nones = as.numeric(reltrad == "No Religion"))
# 2) Compute weighted mean + 84% CI by year x generation (2016+)
gen_nones_ci <- gss_gen_rel %>%
filter(year >= 2016, !is.na(gen)) %>%
group_by(year, gen) %>%
mean_ci(nones, wt = wtssnrps, ci = .84) %>% # returns mean, sd, n, se, lower, upper (per your function)
ungroup()
gen_nones_ci %>%
ggplot(aes(x = factor(year), y = mean, fill = factor(year))) +
geom_col(color = "black") +
geom_errorbar(aes(ymin = lower, ymax = upper), width = .2, linewidth = .6) +
theme_rb() +
# --- white text for darker (early) bars, black for lighter ones ---
geom_text(
aes(
y = 0.04,
label = paste0(round(mean * 100, 0), "%"),
color = factor(year)
),
size = 6, family = "font"
) +
scale_color_manual(
values = c(
# adjust the number of colors to your years
"2016" = "white",
"2018" = "white",
"2021" = "white",
"2022" = "black",
"2024" = "black"
),
guide = "none"
) +
scale_fill_viridis_d(option = "magma", begin = 0.1, end = 0.9) +
scale_y_continuous(labels = scales::percent, limits = c(0, 0.70)) +
facet_wrap(~ gen) +
labs(
x = "Year", y = "",
title = "Share Non-Religious by Generation, 2016–2024",
fill = "Year",
caption = "@ryanburge | Data: General Social Survey, 2016–2024"
)
save("gss_nones_by_generation_2016_2024_with84CI.png", ht = 8)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment