Skip to content

Instantly share code, notes, and snippets.

@ryanburge
Created September 15, 2025 15:28
Show Gist options
  • Select an option

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

Select an option

Save ryanburge/b3fd0dc0b69930959fc628c1d4357009 to your computer and use it in GitHub Desktop.
gg1 <- cces %>%
filter(year == 2008 | year == 2024) %>%
mutate(race = frcode(race == 1 ~ "White",
race != 1 ~ "Non-White")) %>%
filter(pid7 == 1 | pid7 == 2 | pid7 == 3) %>%
cces_attend(pew_attendance) %>%
group_by(year, race) %>%
ct(att, wt = weight, show_na = FALSE)
gg1 %>%
mutate(lab = round(pct, 2)) %>%
mutate(year = as.factor(year)) %>%
ggplot(., aes(x = fct_rev(race), y = pct, fill = fct_rev(att))) +
geom_col(color = "black") +
coord_flip() +
facet_wrap(~ year, ncol =1, strip.position = "top") +
theme_rb() +
scale_fill_manual(values = c(moma.colors("OKeeffe", 6))) +
theme(legend.position = "bottom") +
scale_y_continuous(labels = percent) +
theme(strip.text.y.left = element_text(angle=0)) +
guides(fill = guide_legend(reverse=T, nrow = 1)) +
# theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
theme(panel.grid.minor.y=element_blank(), panel.grid.major.y=element_blank()) +
geom_text(aes(label = ifelse(pct >.05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "black") +
geom_text(aes(label = ifelse(att == "Seldom" & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "white") +
geom_text(aes(label = ifelse(att == "Yearly" & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "white") +
theme(plot.title = element_text(size = 16)) +
theme(strip.text.y.left = element_text(angle = 0, hjust = 1)) +
labs(x = "", y = "", title = "Religious Attendance of Democrats by Race, 2008 vs 2024", caption = "@ryanburge\nData: Cooperative Election Study, 2008-2024")
save("attend_democrats_race_compare.png", wd = 9, ht = 4.5)
gg1 <- cces %>%
filter(year == 2008 | year == 2024) %>%
mutate(race = frcode(race == 1 ~ "White",
race != 1 ~ "Non-White")) %>%
filter(pid7 == 1 | pid7 == 2 | pid7 == 3) %>%
mutate(relig = frcode(religion == 1 ~ "Protestant",
religion == 2 ~ "Catholic",
religion >= 3 & religion <= 8 ~ "Other World Religions",
religion == 9 | religion == 10 ~ "Atheist/Agnostic",
religion == 11 ~ "Nothing in Part.")) %>%
group_by(year, race) %>%
ct(relig, wt = weight, show_na = FALSE)
colors <- c(
"Protestant" = "#1f78b4", # Blue
"Catholic" = "#33a02c", # Green
"Other World Religions" = "#e31a1c", # Red
"Atheist/Agnostic" = "#ff7f00", # Orange
"Nothing in Part." = "#6a3d9a" # Purple
)
gg1 %>%
mutate(lab = round(pct, 2)) %>%
mutate(year = as.factor(year)) %>%
ggplot(., aes(x = fct_rev(race), y = pct, fill = fct_rev(relig))) +
geom_col(color = "black") +
coord_flip() +
facet_wrap(~ year, ncol =1, strip.position = "top") +
theme_rb() +
scale_fill_manual(values = colors) +
theme(legend.position = "bottom") +
scale_y_continuous(labels = percent) +
theme(strip.text.y.left = element_text(angle=0)) +
guides(fill = guide_legend(reverse=T, nrow = 1)) +
# theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
theme(panel.grid.minor.y=element_blank(), panel.grid.major.y=element_blank()) +
geom_text(aes(label = ifelse(pct >.05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 9, family = "font", color = "black") +
geom_text(aes(label = ifelse(relig == "Nothing in Part." & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 9, family = "font", color = "white") +
geom_text(aes(label = ifelse(relig == "Protestant" & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 9, family = "font", color = "white") +
theme(plot.title = element_text(size = 16)) +
theme(strip.text.y.left = element_text(angle = 0, hjust = 1)) +
labs(x = "", y = "", title = "Religious Composition of Democrats by Race, 2008 vs 2024", caption = "@ryanburge\nData: Cooperative Election Study, 2008-2024")
save("relig_democrats_race_compare.png", wd = 9, ht = 4.5)
gg1 <- cces %>%
filter(year == 2008 | year == 2024) %>%
cces_race(race) %>%
filter(pid7 == 1 | pid7 == 2 | pid7 == 3) %>%
mutate(relig = frcode(religion == 1 ~ "Protestant",
religion == 2 ~ "Catholic",
religion >= 3 & religion <= 8 ~ "Other World Religions",
religion == 9 | religion == 10 ~ "Atheist/Agnostic",
religion == 11 ~ "Nothing in Part.")) %>%
group_by(year, race) %>%
ct(relig, wt = weight, show_na = FALSE)
colors <- c(
"Protestant" = "#1f78b4", # Blue
"Catholic" = "#33a02c", # Green
"Other World Religions" = "#e31a1c", # Red
"Atheist/Agnostic" = "#ff7f00", # Orange
"Nothing in Part." = "#6a3d9a" # Purple
)
gg1 %>%
mutate(lab = round(pct, 2)) %>%
mutate(year = as.factor(year)) %>%
ggplot(., aes(x = fct_rev(year), y = pct, fill = fct_rev(relig))) +
geom_col(color = "black") +
coord_flip() +
facet_wrap(~ race, ncol =1, strip.position = "top") +
theme_rb() +
scale_fill_manual(values = colors) +
theme(legend.position = "bottom") +
scale_y_continuous(labels = percent) +
theme(strip.text.y.left = element_text(angle=0)) +
guides(fill = guide_legend(reverse=T, nrow = 1)) +
# theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
theme(panel.grid.minor.y=element_blank(), panel.grid.major.y=element_blank()) +
geom_text(aes(label = ifelse(pct >.05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "black") +
geom_text(aes(label = ifelse(relig == "Nothing in Part." & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "white") +
geom_text(aes(label = ifelse(relig == "Protestant" & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "white") +
theme(plot.title = element_text(size = 16)) +
theme(strip.text.y.left = element_text(angle = 0, hjust = 1)) +
labs(x = "", y = "", title = "Religious Composition of Democrats by Race, 2008 vs 2024", caption = "@ryanburge\nData: Cooperative Election Study, 2008-2024")
save("relig_democrats_race_compare_allraces.png", wd = 9, ht = 7.5)
gg2 <- cces %>%
mutate(race = frcode(race == 1 ~ "White",
race != 1 ~ "Non-White")) %>%
filter(pid7 == 1 | pid7 == 2 | pid7 == 3) %>%
mutate(vimp = case_when(pew_importance == 1 ~ 1,
pew_importance == 2 | pew_importance == 3 | pew_importance == 4 ~ 0)) %>%
group_by(year, race) %>%
mean_ci(vimp, wt = weight, ci = .84) %>%
filter(race != "NA") %>%
select(race, year, imp = mean)
gg3 <- cces %>%
filter(year >= 2008) %>%
mutate(race = frcode(race == 1 ~ "White",
race != 1 ~ "Non-White")) %>%
filter(pid7 == 1 | pid7 == 2 | pid7 == 3) %>%
mutate(wk = case_when(pew_attendance == 1 | pew_attendance == 2 ~ 1,
pew_attendance <= 6 ~ 0)) %>%
filter(pid3 != "NA") %>%
group_by(race, year) %>%
mean_ci(wk, wt = weight, ci = .84) %>%
select(race, year, wk = mean)
graph <- left_join(gg2, gg3) %>% na.omit()
library(dplyr)
library(ggplot2)
library(grid)
# Compute predicted fit lines with imp sequence going from max to min (for arrow direction)
fit_lines <- graph %>%
group_by(race) %>%
do({
mod <- lm(wk ~ imp, data = .)
imp_seq <- seq(max(.$imp), min(.$imp), length.out = 100) # reverse seq
tibble(imp = imp_seq, wk = predict(mod, newdata = data.frame(imp = imp_seq)))
})
pres_years <- c(2008, 2012, 2016, 2020, 2024)
graph %>%
ggplot(aes(x = imp, y = wk, color = race, group = race)) +
geom_point(stroke = 1, shape = 21, show.legend = FALSE) +
geom_path(data = fit_lines, aes(x = imp, y = wk, color = race),
arrow = arrow(length = unit(0.15, "inches"), type = "closed"), size = 1) +
theme_rb() +
geom_text_repel(
data = filter(graph, year %in% pres_years),
aes(label = year),
family = "font",
size = 5
) +
add_text(y = .225, x = .225, word = "White", sz = 10) +
add_text(y = .35, x = .45, word = "Non-White", sz = 10) +
scale_color_calc() +
scale_x_continuous(labels = scales::percent_format(), breaks = c(.25, .35, .45, .55)) +
scale_y_continuous(labels = scales::percent_format(), limits = c(0, .5)) +
labs(
x = "Share Saying Religion is Very Important",
y = "Share Attending Services Weekly",
title = "Religion Importance and Religious Attendance among Democrats by Race",
caption = "@ryanburge\nData: Cooperative Election Study, 2008-2024"
)
save("scatter_imp_att_race_dems.png")
gg1 <- cces %>%
filter(year == 2008 | year == 2024) %>%
mutate(race = frcode(race == 1 ~ "White",
race != 1 ~ "Non-White")) %>%
filter(pid7 == 1 | pid7 == 2 | pid7 == 3) %>%
mutate(rel = frcode(religion <= 8 ~ "Religious",
religion == 9 | religion == 10 | religion == 11 ~ "Non-Religious")) %>%
mutate(id5 = frcode(ideo5 == 1 ~ "Very Liberal",
ideo5 == 2 ~ "Liberal",
ideo5 == 3 ~ "Moderate",
ideo5 == 4 ~ "Conservative",
ideo5 == 5 ~ "Very Conservative")) %>%
group_by(year, race, rel) %>%
ct(id5, wt = weight, show_na = FALSE)
library(ggplot2)
library(scales) # for percent formatting
library(forcats) # for factor reordering
# Reorder id5 from Very Liberal to Very Conservative
gg1 <- gg1 %>%
filter(rel != 'NA') %>%
mutate(id5 = factor(id5, levels = c("Very Liberal", "Liberal", "Moderate", "Conservative", "Very Conservative")))
colors <- c(
"Very Liberal" = "#2166ac", # Deep blue
"Liberal" = "#67a9cf", # Lighter blue
"Moderate" = "#f7f7f7", # Light gray/neutral
"Conservative" = "#f4a582", # Light red/orange
"Very Conservative" = "#b2182b" # Deep red
)
gg1 %>%
mutate(lab = round(pct, 2)) %>%
mutate(year = as.factor(year)) %>%
ggplot(., aes(x = fct_rev(year), y = pct, fill = fct_rev(id5))) +
geom_col(color = "black") +
coord_flip() +
facet_grid(rel ~ race) +
theme_rb() +
scale_fill_manual(values = colors) +
theme(legend.position = "bottom") +
scale_y_continuous(labels = percent) +
theme(strip.text.y.left = element_text(angle=0)) +
guides(fill = guide_legend(reverse=T, nrow = 1)) +
# theme(axis.title.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank()) +
theme(panel.grid.minor.y=element_blank(), panel.grid.major.y=element_blank()) +
geom_text(aes(label = ifelse(pct >.075, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "black") +
geom_text(aes(label = ifelse(pct >.075 & id5 == "Very Liberal", paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "white") +
# geom_text(aes(label = ifelse(att == "Yearly" & pct > .05, paste0(lab*100, '%'), '')), position = position_stack(vjust = 0.5), size = 8, family = "font", color = "white") +
theme(plot.title = element_text(size = 16)) +
theme(strip.text.y.left = element_text(angle = 0, hjust = 1)) +
labs(x = "", y = "", title = "The Political Ideology of Democrats by Race and Religion", caption = "@ryanburge\nData: Cooperative Election Study, 2008-2024")
save("relig_democrats_race_compare_allracesnn.png", wd = 10, ht = 4.5)
dvs_summary <- cces24 %>%
filter(pid7 %in% 1:3) %>%
mutate(religion = religpew) %>%
mutate(
race = frcode(race == 1 ~ "White", race != 1 ~ "Non-White"),
rel = frcode(religion <= 8 ~ "Religious",
religion == 9 | religion == 10 | religion == 11 ~ "Non-Religious"),
cc444a = ifelse(CC24_444a == 1, 1, 0),
cc444b = ifelse(CC24_444b == 1, 1, 0),
cc444c = ifelse(CC24_444c == 1, 1, 0),
cc444d = ifelse(CC24_444d == 1, 1, 0),
cc444e = ifelse(CC24_444e == 1, 1, 0),
cc444f = ifelse(CC24_444f == 1, 1, 0)
) %>%
select(commonweight, race, rel, starts_with("cc444")) %>%
pivot_longer(
cols = starts_with("cc444"),
names_to = "item",
values_to = "support"
) %>%
group_by(race, rel, item) %>%
mean_ci(support, wt = commonweight) %>%
ungroup() %>%
mutate(
type = case_when(
item == "cc444a" ~ "Ban gender transition\nfor minors",
item == "cc444b" ~ "Parental consent\nfor pronoun changes",
item == "cc444c" ~ "Ban abortion\npills by mail",
item == "cc444d" ~ "Ban out-of-state\nabortions",
item == "cc444e" ~ "Require age\nchecks for porn",
item == "cc444f" ~ "Support school\nvouchers"
)
)
dvs_summary <- dvs_summary %>%
filter(race != "NA") %>%
filter(rel != "NA") %>%
mutate(race_rel = paste(race, rel, sep = " \n"))
colors <- c(
"White \nReligious" = "#2c7fb8", # Medium blue
"White \nNon-Religious" = "#7fcdbb", # Light teal
"Non-White \nReligious" = "#e08214", # Bright orange
"Non-White \nNon-Religious" = "#fdb863" # Light orange/yellow
)
ggplot(dvs_summary, aes(x = fct_rev(race_rel), y = mean, fill = race_rel)) +
geom_col(color = "black") +
facet_wrap(~ type, ncol = 2) +
scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
labs(
x = "",
y = "",
fill = "Group",
title = "Support for Policies by Combined Race & Religion Groups among Democrats",
caption = "@ryanburge | Data: Cooperative Election Study 2024"
) +
theme_rb() +
scale_fill_manual(values = colors) +
lab_bar(above = TRUE, type = mean, pos = .065, sz = 9)
save("issue_compares_dem_race_relig.png", ht = 11, wd = 7.5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment