Skip to content

Instantly share code, notes, and snippets.

@ryanburge
Created March 28, 2026 22:17
Show Gist options
  • Select an option

  • Save ryanburge/7dac81aa49011a2b7023cde4ce0104e8 to your computer and use it in GitHub Desktop.

Select an option

Save ryanburge/7dac81aa49011a2b7023cde4ce0104e8 to your computer and use it in GitHub Desktop.
aaa1 <- cces23 %>%
mutate(vv = CC23_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1,
vv == 2 ~ 0)) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(type = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition") %>%
mutate(year = 2023)
aaa2 <- cces25 %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1,
vv == 2 ~ 0)) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(type = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition") %>%
mutate(year = 2025)
one <- bind_rows(aaa1, aaa2) %>% mutate(pid3 = "Full Sample")
aaa1 <- cces23 %>%
mutate(vv = CC23_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1,
vv == 2 ~ 0)) %>%
cces_pid3(pid7) %>%
group_by(pid3) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(type = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition") %>%
mutate(year = 2023)
aaa2 <- cces25 %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1,
vv == 2 ~ 0)) %>%
cces_pid3(pid7) %>%
group_by(pid3) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(type = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition") %>%
mutate(year = 2025)
two <- bind_rows(aaa1, aaa2)
all <- bind_rows(one, two) %>% filter(pid3 != "NA")
all %>%
mutate(pid3 = factor(pid3, levels = c("Full Sample", "Democrat", "Independent", "Republican"))) %>%
filter(!is.na(pid3)) %>%
ggplot(., aes(x = factor(year), y = mean, fill = pid3)) +
geom_col(color = "black") +
facet_wrap(~ pid3, nrow = 1) +
scale_fill_manual(values = c(
"Full Sample" = "azure4",
"Democrat" = "dodgerblue",
"Independent" = "darkorchid",
"Republican" = "firebrick"
)) +
theme_rb() +
lab_bar_white(above = FALSE, type = mean, pos = .05, sz = 10) +
error_bar() +
theme(axis.text.x = element_text(size = 20)) +
y_pct() +
labs(x = "", y = "", title = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition",
caption= "@ryanburge | Data: Cooperative Election Study, 2023-2025")
save("ces_trans_chagne.png")
aaa1 <- cces23 %>%
mutate(vv = CC23_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2023)
aaa2 <- cces25 %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2025)
one <- bind_rows(aaa1, aaa2) %>% mutate(gen = "Full Sample")
aaa1 <- cces23 %>%
mutate(vv = CC23_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
mutate(gen = frcode(birthyr >= 1997 ~ "Gen Z",
birthyr >= 1981 ~ "Millennial",
birthyr >= 1965 ~ "Gen X",
birthyr >= 1946 ~ "Boomer",
birthyr < 1946 ~ "Silent/Greatest")) %>%
group_by(gen) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2023)
aaa2 <- cces25 %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
mutate(gen = frcode(birthyr >= 1997 ~ "Gen Z",
birthyr >= 1981 ~ "Millennial",
birthyr >= 1965 ~ "Gen X",
birthyr >= 1946 ~ "Boomer",
birthyr < 1946 ~ "Silent/Greatest")) %>%
group_by(gen) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2025)
two <- bind_rows(aaa1, aaa2)
all <- bind_rows(one, two) %>% filter(!is.na(gen))
two %>%
mutate(gen = factor(gen, levels = c("Silent/Greatest", "Boomer", "Gen X", "Millennial", "Gen Z"))) %>%
ggplot(., aes(x = factor(year), y = mean, fill = gen)) +
geom_col(color = "black") +
facet_wrap(~ gen, nrow = 1) +
scale_fill_manual(values = c(
"Gen Z" = "#4e79a7",
"Millennial" = "#f28e2b",
"Gen X" = "#59a14f",
"Boomer" = "#e15759",
"Silent/Greatest" = "#b07aa1"
)) +
theme_rb() +
lab_bar_white(above = FALSE, type = mean, pos = .05, sz = 10) +
error_bar() +
theme(axis.text.x = element_text(size = 20)) +
y_pct() +
labs(x = "", y = "",
title = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition",
caption = "@ryanburge | Data: Cooperative Election Study, 2023-2025")
save("ces_trans_gen.png", wd = 12, ht = 6)
gg1 <- reltrad(cces23, "23") %>%
mutate(vv = CC23_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
group_by(trad2) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2023)
gg2 <- reltrad(cces25, "25") %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
group_by(trad2) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2025)
all <- bind_rows(gg1, gg2)
all %>%
filter(!is.na(trad2)) %>%
mutate(lab = round(mean * 100)) %>%
ggplot(., aes(x = fct_rev(trad2), y = mean, color = factor(year))) +
geom_pointrange(data = . %>% filter(year == 2025),
aes(ymin = lower, ymax = upper),
position = position_nudge(x = 0.15), size = 0.8) +
geom_pointrange(data = . %>% filter(year == 2023),
aes(ymin = lower, ymax = upper),
position = position_nudge(x = -0.15), size = 0.8) +
geom_text(data = . %>% filter(year == 2025),
aes(label = paste0(lab, "%"), y = mean),
position = position_nudge(x = 0.55),
hjust = 0.5, size = 3.5, family = "bold", show.legend = FALSE) +
geom_text(data = . %>% filter(year == 2023),
aes(label = paste0(lab, "%"), y = mean),
position = position_nudge(x = -0.55),
hjust = 0.5, size = 3.5, family = "bold", show.legend = FALSE) +
coord_flip() +
theme_rb(legend = TRUE) +
y_pct() +
scale_color_d3(breaks = c("2025", "2023")) +
# guides(color = guide_legend(reverse = TRUE)) +
theme(legend.text = element_text(size = 20)) +
labs(x = "", y = "", color = "",
title = "Support for Banning Gender-Affirming Care for Minors by Religious Tradition",
caption = "@ryanburge | Data: Cooperative Election Study, 2023-2025")
save("ces_trans_trad2.png", wd = 10, ht = 8)
gg1 <- cces23 %>%
cces_trad(religpew) %>%
mutate(vv = CC23_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
cces_pid3(pid7) %>%
group_by(trad2, pid3) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2023)
gg2 <- cces25 %>%
cces_trad(religpew) %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1, vv == 2 ~ 0)) %>%
cces_pid3(pid7) %>%
group_by(trad2, pid3) %>%
mean_ci(vv, wt = commonweight, ci = .84) %>%
mutate(year = 2025)
bind_rows(gg1, gg2) %>%
filter(pid3 != "NA", !is.na(trad2)) %>%
mutate(lab = round(mean, 2)) %>%
ggplot(., aes(x = factor(year), y = mean, fill = pid3)) +
geom_col(color = "black") +
facet_grid(trad2 ~ pid3) +
pid3_fill() +
theme_rb() +
y_pct() +
error_bar() +
lab_bar(above = FALSE, type = lab, pos = .08, sz = 5) +
labs(x = "", y = "Share Agreeing",
title = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("pid3_trans_minor_trad2_change.png", wd = 10, ht = 14)
plot_data <- bind_rows(gg1, gg2) %>%
filter(pid3 != "NA", pid3 != "Independent", !is.na(trad2)) %>%
filter(!trad2 %in% c("Orthodox", "Muslim", "Buddhist", "Hindu", "Unclassified")) %>%
mutate(trad2 = droplevels(fct_rev(trad2))) %>%
select(trad2, pid3, mean, year) %>%
pivot_wider(names_from = year, values_from = mean, names_prefix = "yr_") %>%
mutate(y_base = as.numeric(trad2),
y_pos = case_when(pid3 == "Democrat" ~ y_base + 0.2,
pid3 == "Republican" ~ y_base - 0.2))
trad_labels <- levels(plot_data$trad2)
plot_data %>%
ggplot(., aes(color = pid3)) +
geom_segment(aes(x = yr_2023,
xend = yr_2025 - (yr_2025 - yr_2023) * 0.1,
y = y_pos, yend = y_pos),
linewidth = 1,
arrow = arrow(length = unit(0.3, "cm"), type = "open", ends = "last")) +
geom_point(aes(x = yr_2023, y = y_pos), shape = 21, fill = "white", size = 3) +
geom_point(aes(x = yr_2025, y = y_pos), shape = 19, size = 3) +
scale_y_continuous(breaks = seq_along(trad_labels), labels = trad_labels) +
scale_color_manual(values = c("dodgerblue4", 'firebrick3')) +
theme_rb(legend = TRUE) +
theme(legend.text = element_text(size = 20)) +
x_pct() +
labs(x = "", y = "", color = "",
title = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition",
subtitle = "Open circle = 2023, Filled circle = 2025",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("pid3_trans_minor_trad2_dumbbell.png", wd = 10, ht = 6)
library(fst)
library(tidyverse)
source("https://gist.githubusercontent.com/ryanburge/4bb20dbacfb068949dee4fe42fbd490b/raw/rb_functions2026.R")
# Load data
ces23 <- read_fst("E://data/cces23.fst")
ces25 <- read_fst("E://data/cces25.fst")
# Recode and stack
ces23_r <- ces23 %>%
mutate(
year = 0,
outcome = case_when(CC23_343a == 1 ~ 1, CC23_343a == 2 ~ 0, TRUE ~ NA_real_),
female = case_when(gender4 == 2 ~ 1, gender4 == 1 ~ 0, TRUE ~ NA_real_),
age = 2023 - birthyr,
educ = ifelse(educ %in% c(98, 99), NA, educ),
faminc = ifelse(faminc_new %in% c(97, 998, 999), NA, faminc_new),
pid7 = ifelse(pid7 %in% c(8, 9, 98, 99), NA, pid7),
ideo5 = ifelse(ideo5 %in% c(6, 8, 9), NA, ideo5),
attend = ifelse(pew_churatd %in% c(7, 98, 99), NA, pew_churatd),
religimp = ifelse(pew_religimp %in% c(8, 9), NA, pew_religimp),
bornagain = case_when(pew_bornagain == 1 ~ 1, pew_bornagain == 2 ~ 0, TRUE ~ NA_real_),
white = case_when(race == 1 ~ 1, TRUE ~ 0),
black = case_when(race == 2 ~ 1, TRUE ~ 0),
hispanic = case_when(race == 3 ~ 1, TRUE ~ 0),
weight = commonweight
) %>%
select(year, outcome, female, age, educ, faminc, pid7, ideo5,
attend, religimp, bornagain, white, black, hispanic, weight)
ces25_r <- ces25 %>%
mutate(
year = 1,
outcome = case_when(CC25_343a == 1 ~ 1, CC25_343a == 2 ~ 0, TRUE ~ NA_real_),
female = case_when(gender4 == 2 ~ 1, gender4 == 1 ~ 0, TRUE ~ NA_real_),
age = 2025 - birthyr,
educ = ifelse(educ %in% c(98, 99), NA, educ),
faminc = ifelse(faminc_new %in% c(97, 998, 999), NA, faminc_new),
pid7 = ifelse(pid7 %in% c(8, 9, 98, 99), NA, pid7),
ideo5 = ifelse(ideo5 %in% c(6, 8, 9), NA, ideo5),
attend = ifelse(pew_churatd %in% c(7, 98, 99), NA, pew_churatd),
religimp = ifelse(pew_religimp %in% c(8, 9), NA, pew_religimp),
bornagain = case_when(pew_bornagain == 1 ~ 1, pew_bornagain == 2 ~ 0, TRUE ~ NA_real_),
white = case_when(race == 1 ~ 1, TRUE ~ 0),
black = case_when(race == 2 ~ 1, TRUE ~ 0),
hispanic = case_when(race == 3 ~ 1, TRUE ~ 0),
weight = commonweight
) %>%
select(year, outcome, female, age, educ, faminc, pid7, ideo5,
attend, religimp, bornagain, white, black, hispanic, weight)
stacked <- bind_rows(ces23_r, ces25_r)
# LPM with year interactions — interaction coefs = what drove the shift
m1 <- lm(outcome ~ year * (female + age + educ + faminc + pid7 + ideo5 +
attend + religimp + bornagain + white + black + hispanic),
data = stacked, weights = weight)
summary(m1)
library(broom)
tidy(m1) %>%
filter(str_detect(term, "year:")) %>%
mutate(
term = str_remove(term, "year:"),
term = frcode(
term == "female" ~ "Female",
term == "age" ~ "Age",
term == "educ" ~ "Education",
term == "faminc" ~ "Family Income",
term == "pid7" ~ "Party ID (Rep. direction)",
term == "ideo5" ~ "Ideology (Con. direction)",
term == "attend" ~ "Church Attendance",
term == "religimp" ~ "Religion Less Important",
term == "bornagain" ~ "Born Again",
term == "white" ~ "White",
term == "black" ~ "Black",
term == "hispanic" ~ "Hispanic"
),
sig = p.value < 0.05,
conf.low = estimate - 1.96 * std.error,
conf.high = estimate + 1.96 * std.error
) %>%
ggplot(aes(x = estimate, y = fct_reorder(term, estimate), color = sig)) +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray50") +
geom_pointrange(aes(xmin = conf.low, xmax = conf.high), size = 0.6) +
scale_color_manual(values = c("FALSE" = "gray60", "TRUE" = "firebrick")) +
theme_rb(legend = FALSE) +
labs(x = "Change in Predicted Support (2023 to 2025)",
y = "",
title = "What drove the shift in support for gender-affirming care bans?",
subtitle = "Interaction coefficients from DiD regression (significant terms in red)",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("trans_did_coefplot.png", wd = 9, ht = 6)
# Standardize continuous predictors
stacked_z <- stacked %>%
mutate(across(c(age, educ, faminc, pid7, ideo5, attend, religimp), scale))
stacked_z <- stacked %>%
mutate(
religimp = 5 - religimp # now 4 = very important, 1 = not at all
) %>%
mutate(across(c(age, educ, faminc, pid7, ideo5, attend, religimp), scale))
# Rerun model with standardized predictors
m2 <- lm(outcome ~ year * (female + age + educ + faminc + pid7 + ideo5 +
attend + religimp + bornagain + white + black + hispanic),
data = stacked_z, weights = weight)
# Plot interactions only
tidy(m2) %>%
filter(str_detect(term, "year:")) %>%
mutate(
term = str_remove(term, "year:"),
term = frcode(
term == "female" ~ "Female",
term == "age" ~ "Age",
term == "educ" ~ "Education",
term == "faminc" ~ "Family Income",
term == "pid7" ~ "Party ID (Rep. direction)",
term == "ideo5" ~ "Ideology (Con. direction)",
term == "attend" ~ "Church Attendance",
term == "religimp" ~ "Religion Less Important",
term == "bornagain" ~ "Born Again",
term == "white" ~ "White",
term == "black" ~ "Black",
term == "hispanic" ~ "Hispanic"
),
sig = p.value < 0.05,
conf.low = estimate - 1.96 * std.error,
conf.high = estimate + 1.96 * std.error
) %>%
ggplot(aes(x = estimate, y = fct_reorder(term, estimate), color = sig)) +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray50") +
geom_pointrange(aes(xmin = conf.low, xmax = conf.high), size = 0.6) +
# geom_text(aes(label = round(estimate, 3)), hjust = -0.3, size = 3.5, color = "black") +
scale_color_manual(values = c("FALSE" = "gray60", "TRUE" = "firebrick")) +
theme_rb(legend = FALSE) +
labs(x = "Standardized Change in Predicted Support (2023 to 2025)",
y = "",
title = "What drove the shift in support for gender-affirming care bans?",
subtitle = "Standardized interaction coefficients — significant terms in red",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("trans_did_coefplot_std.png", wd = 9, ht = 5)
gg1 <- cces25 %>%
cces_trad(religpew) %>%
mutate(vv = CC25_343a) %>%
mutate(vv = case_when(vv == 1 ~ 1,
vv == 2 ~ 0)) %>%
# group_by(trad2) %>%
mean_ci(vv, wt = commonweight, ci = .84)
trad2_colors <- c(
"White Evangelical" = "#E8A87C",
"Non-White Evangelical" = "#F5C9A0",
"Mainline" = "#85B8E8",
"Black Protestant" = "#6A9FD4",
"White Catholic" = "#B39DDB",
"Non-White Catholic" = "#CDB8E8",
"LDS" = "#80CBC4",
"Orthodox" = "#FFE082",
"Jewish" = "#A5D6A7",
"Muslim" = "#80C9A0",
"Buddhist" = "#B2DFDB",
"Hindu" = "#FFCC80",
"Atheist" = "#9E9E9E",
"Agnostic" = "#BDBDBD",
"Nothing in Particular" = "#D4D4D4",
"Unclassified" = "#E8E8E4"
)
gg1 %>%
ggplot(., aes(x = reorder(trad2, mean), y = mean, fill = trad2)) +
geom_col(color = "black") +
coord_flip() +
theme_rb() +
y_pct() +
error_bar() +
scale_fill_manual(values = trad2_colors) +
lab_bar(above = FALSE, type = mean, pos = .05, sz = 7) +
labs(x = "", y = "", title = "Make it illegal for health care professionals to provide someone younger\nthan 18 with medical care for a gender transition",
caption = "@ryanburge | Data: Cooperative Election Study, 2025")
save("gender_transitition_ces25_trad2.png")
ces23_gen <- ces23 %>%
mutate(
year = "2023",
outcome = case_when(CC23_343a == 1 ~ 1, CC23_343a == 2 ~ 0, TRUE ~ NA_real_),
gender = case_when(gender4 == 1 ~ "Man", gender4 == 2 ~ "Woman", TRUE ~ NA_character_),
generation = case_when(
birthyr <= 1945 ~ "Silent/Greatest",
birthyr <= 1964 ~ "Boomer",
birthyr <= 1980 ~ "Gen X",
birthyr <= 1996 ~ "Millennial",
birthyr <= 2012 ~ "Gen Z",
TRUE ~ NA_character_
),
weight = commonweight
) %>%
filter(!is.na(outcome), !is.na(gender), !is.na(generation)) %>%
group_by(year, generation, gender) %>%
mean_ci(outcome, wt = weight)
ces25_gen <- ces25 %>%
mutate(
year = "2025",
outcome = case_when(CC25_343a == 1 ~ 1, CC25_343a == 2 ~ 0, TRUE ~ NA_real_),
gender = case_when(gender4 == 1 ~ "Man", gender4 == 2 ~ "Woman", TRUE ~ NA_character_),
generation = case_when(
birthyr <= 1945 ~ "Silent/Greatest",
birthyr <= 1964 ~ "Boomer",
birthyr <= 1980 ~ "Gen X",
birthyr <= 1996 ~ "Millennial",
birthyr <= 2012 ~ "Gen Z",
TRUE ~ NA_character_
),
weight = commonweight
) %>%
filter(!is.na(outcome), !is.na(gender), !is.na(generation)) %>%
group_by(year, generation, gender) %>%
mean_ci(outcome, wt = weight)
gg <- bind_rows(ces23_gen, ces25_gen) %>%
mutate(
generation = frcode(
generation == "Silent/Greatest" ~ "Silent/Greatest",
generation == "Boomer" ~ "Boomer",
generation == "Gen X" ~ "Gen X",
generation == "Millennial" ~ "Millennial",
generation == "Gen Z" ~ "Gen Z"
),
gender = factor(gender, levels = c("Woman", "Man"))
)
plot_data <- gg %>%
pivot_wider(names_from = year, values_from = mean, names_prefix = "yr_") %>%
mutate(y_pos = as.numeric(gender))
gender_labels <- levels(plot_data$gender)
plot_data %>%
ggplot(aes(color = gender)) +
geom_segment(aes(x = yr_2023,
xend = yr_2025 - (yr_2025 - yr_2023) * 0.1,
y = y_pos, yend = y_pos),
linewidth = 1,
arrow = arrow(length = unit(0.3, "cm"), type = "open", ends = "last")) +
geom_point(aes(x = yr_2023, y = y_pos), shape = 21, fill = "white", size = 3) +
geom_point(aes(x = yr_2025, y = y_pos), shape = 19, size = 3) +
scale_y_continuous(breaks = seq_along(gender_labels), labels = gender_labels) +
facet_wrap(~ generation, ncol = 5) +
scale_color_manual(values = c("Man" = "steelblue", "Woman" = "firebrick")) +
theme_rb(legend = TRUE) +
x_pct() +
labs(x = "", y = "", color = "",
title = "Support for gender-affirming care ban by generation and gender",
subtitle = "Open circle = 2023, Filled circle = 2025",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("trans_gen_gender.png", wd = 14, ht = 5)
ces25 %>%
mutate(
outcome = case_when(CC25_343a == 1 ~ 1, CC25_343a == 2 ~ 0, TRUE ~ NA_real_),
gender = case_when(gender4 == 1 ~ "Man", gender4 == 2 ~ "Woman", TRUE ~ NA_character_),
generation = case_when(
birthyr <= 1945 ~ "Silent/Greatest",
birthyr <= 1964 ~ "Boomer",
birthyr <= 1980 ~ "Gen X",
birthyr <= 1996 ~ "Millennial",
birthyr <= 2012 ~ "Gen Z",
TRUE ~ NA_character_
),
generation = frcode(
generation == "Silent/Greatest" ~ "Silent/Greatest",
generation == "Boomer" ~ "Boomer",
generation == "Gen X" ~ "Gen X",
generation == "Millennial" ~ "Millennial",
generation == "Gen Z" ~ "Gen Z"
)
) %>%
filter(!is.na(outcome), !is.na(gender), !is.na(generation)) %>%
group_by(generation, gender) %>%
mean_ci(outcome, wt = commonweight, ci = .84) %>%
ggplot(aes(x = mean, y = fct_rev(generation), color = gender)) +
geom_pointrange(aes(xmin = lower, xmax = upper),
position = position_dodge(width = 0.4), size = 0.6, stroke = 1, shape = 21, fill = 'white') +
geom_text(data = . %>% filter(gender == "Woman"),
aes(label = paste0(round(mean * 100, 0), "%")),
position = position_dodge(width = 0.4),
vjust = -1.6, size = 3.5, fontface = "bold", show.legend = FALSE) +
geom_text(data = . %>% filter(gender == "Man"),
aes(label = paste0(round(mean * 100, 0), "%")),
position = position_dodge(width = 0.4),
vjust = 2.6, size = 3.5, fontface = "bold", show.legend = FALSE) +
scale_color_calc() +
guides(color = guide_legend(reverse = TRUE)) +
theme_rb(legend = TRUE) +
theme(legend.text = element_text(size = 20)) +
x_pct() +
labs(x = "", y = "", color = "",
title = "Support for gender-affirming care ban by generation and gender",
caption = "@ryanburge\nData: Cooperative Election Study, 2025")
save("trans_gen_gender_25.png", wd = 9, ht = 6)
bind_rows(
ces23 %>% mutate(year = "2023", outcome = case_when(CC23_343a == 1 ~ 1, CC23_343a == 2 ~ 0, TRUE ~ NA_real_)),
ces25 %>% mutate(year = "2025", outcome = case_when(CC25_343a == 1 ~ 1, CC25_343a == 2 ~ 0, TRUE ~ NA_real_))
) %>%
mutate(
gender = case_when(gender4 == 1 ~ "Man", gender4 == 2 ~ "Woman", TRUE ~ NA_character_),
generation = case_when(
birthyr <= 1945 ~ "Silent/Greatest",
birthyr <= 1964 ~ "Boomer",
birthyr <= 1980 ~ "Gen X",
birthyr <= 1996 ~ "Millennial",
birthyr <= 2012 ~ "Gen Z",
TRUE ~ NA_character_
),
generation = frcode(
generation == "Silent/Greatest" ~ "Silent/Greatest",
generation == "Boomer" ~ "Boomer",
generation == "Gen X" ~ "Gen X",
generation == "Millennial" ~ "Millennial",
generation == "Gen Z" ~ "Gen Z"
),
weight = commonweight
) %>%
filter(!is.na(outcome), !is.na(gender), !is.na(generation)) %>%
group_by(year, generation, gender) %>%
mean_ci(outcome, wt = weight) %>%
select(year, generation, gender, mean) %>%
pivot_wider(names_from = gender, values_from = mean) %>%
mutate(gap = Man - Woman) %>%
ggplot(aes(x = gap, y = fct_rev(generation), color = year, group = year)) +
geom_vline(xintercept = 0, linetype = "dashed", color = "gray50") +
geom_point(size = 4) +
geom_text(aes(label = paste0("+", round(gap * 100, 1), "%")),
vjust = -1.2, size = 3.5, fontface = "bold", show.legend = FALSE) +
scale_color_manual(values = c("2023" = "gray50", "2025" = "firebrick")) +
theme_rb(legend = TRUE) +
x_pct() +
labs(x = "Gap in support (Men minus Women)", y = "", color = "",
title = "The gender gap in support for gender-affirming care bans has collapsed",
subtitle = "Percentage point difference between men and women, by generation",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("trans_gender_gap.png", wd = 9, ht = 6)
gg1 <- bind_rows(
ces23 %>% select(birthyr, gender4, commonweight, CC23_343a) %>%
mutate(year = "2023", outcome = case_when(CC23_343a == 1 ~ 1, CC23_343a == 2 ~ 0, TRUE ~ NA_real_)),
ces25 %>% select(birthyr, gender4, commonweight, CC25_343a) %>%
mutate(year = "2025", outcome = case_when(CC25_343a == 1 ~ 1, CC25_343a == 2 ~ 0, TRUE ~ NA_real_))
) %>%
mutate(
gender = case_when(gender4 == 1 ~ "Man", gender4 == 2 ~ "Woman", TRUE ~ NA_character_),
generation = frcode(
birthyr <= 1964 ~ "Boomer",
birthyr <= 1980 ~ "Gen X",
birthyr <= 1996 ~ "Millennial",
birthyr <= 2012 ~ "Gen Z"
),
weight = commonweight
) %>%
filter(!is.na(outcome), !is.na(gender), !is.na(generation)) %>%
group_by(year, generation, gender) %>%
mean_ci(outcome, wt = weight, ci = .84)
gg1 %>%
ggplot(aes(x = factor(year), y = mean, fill = gender)) +
geom_col(color = "black", position = "dodge") +
facet_wrap(~ generation, ncol = 2) +
scale_fill_calc() +
error_bar() +
guides(fill = guide_legend(reverse = FALSE)) +
theme_rb(legend = TRUE) +
y_pct() +
lab_bar_white(pos = .075, sz = 6, type = mean, above = FALSE) +
theme(plot.title = element_text(size = 12)) +
labs(x = "", y = "", fill = "",
title = "Support for gender-affirming care ban by generation and gender",
caption = "@ryanburge\nData: Cooperative Election Study, 2023 & 2025")
save("trans_gen_gender_bars.png", wd = 6, ht = 6)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment