These graphics show the top five three-word phrases in posts on X.com by Republicans and Democrats in Congress during the eight weeks since the U.S. and Israel attacked Iran. The white space in the lower right could be used to display a less-nerdy title than “Weekly Volume of Core Trigram Concepts …,” perhaps along with a logo for the Social Media Inisghts Lab and a QR code leading to a more detailed report. The more detailed report could elaborate on the trigrams shown and perhaps discuss others that didn’t make the top-five list.
Alternatively, the code can be set to show only the top three
trigrams for each group. This would make things a little less visually
complicated and perhaps allow more room for the title, branding and QR
code:
############################################################
# STEP 0: Load required packages
############################################################
library(dplyr)
library(ggplot2)
library(forcats)
library(stringr)
############################################################
# STEP 1: Load data and restrict weeks
############################################################
All_Trigrams_clean <- readRDS("All_Trigrams_clean.rds")
All_Trigrams_clean <- All_Trigrams_clean %>%
filter(Week > 60)
# All_Trigrams_clean <- All_Trigrams_clean %>%
# filter(str_detect(ngram, regex("epstein", ignore_case = TRUE)))
############################################################
# STEP 1b: MANUAL CONCEPT RECODING (dictionary-style)
############################################################
All_Trigrams_clean <- All_Trigrams_clean %>%
mutate(
ngram_lower = str_to_lower(ngram),
concept = case_when(
str_detect(ngram_lower, "\\bfamilies tax cuts") ~ "families tax cut",
str_detect(ngram_lower, "\\baca tax credits") ~ "affordable care act",
str_detect(ngram_lower, "\\bchild tax credit") ~ "families tax cut",
str_detect(ngram_lower, "\\btax cuts act") ~ "families tax cut",
TRUE ~ ngram
)
)
############################################################
# STEP 1c: MANUAL EXCLUSION OF FRAGMENT NGRAMS
############################################################
All_Trigrams_clean <- All_Trigrams_clean %>%
mutate(
drop_ngram = case_when(
str_detect(ngram_lower, "\\bfree america caucus\\b") ~ TRUE,
str_detect(ngram_lower, "\\bamerica great again\\b") ~ TRUE,
TRUE ~ FALSE
)
) %>%
filter(!drop_ngram)
############################################################
# STEP 2: Identify top N CONCEPTS by party
############################################################
TOP_N <- 5
top_concepts_by_party <- All_Trigrams_clean %>%
filter(!is.na(concept), nchar(concept) > 0) %>%
count(party, concept, sort = TRUE) %>%
group_by(party) %>%
slice_head(n = TOP_N) %>%
ungroup()
############################################################
# STEP 3: Republican weekly concept counts
############################################################
rep_weekly <- All_Trigrams_clean %>%
filter(
party == "Rep",
concept %in% top_concepts_by_party$concept[
top_concepts_by_party$party == "Rep"
]
) %>%
count(WeekStart, concept, name = "weekly_count") %>%
group_by(concept) %>%
mutate(total_mentions = sum(weekly_count)) %>%
ungroup() %>%
arrange(desc(total_mentions)) %>%
mutate(
facet_label = paste0(
concept,
" (", format(total_mentions, big.mark = ","), " mentions)"
),
facet_label = factor(facet_label, levels = unique(facet_label))
)
############################################################
# STEP 4: Republican small-multiple line chart
############################################################
rep_plot <- ggplot(
rep_weekly,
aes(
x = WeekStart,
y = weekly_count,
group = facet_label,
linewidth = total_mentions
)
) +
geom_line(color = "#b11226") +
geom_point(color = "#b11226", size = 2.8) +
facet_wrap(
~ facet_label,
ncol = 2,
scales = "free_y",
labeller = labeller(
facet_label = function(x) str_wrap(x, width = 28)
)
) +
scale_linewidth(
range = c(0.6, 1.8),
guide = "none"
) +
labs(
title = "Weekly Volume of Core Trigram Concepts — Republicans",
x = "Week",
y = "Weekly mentions"
) +
theme_bw(base_size = 12) +
theme(
strip.text = element_text(
size = 10.5,
face = "bold",
lineheight = 1.05
),
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
panel.spacing = unit(1.2, "lines")
)
print(rep_plot)
############################################################
# STEP 5: Democratic / Independent weekly concept counts
############################################################
dem_weekly <- All_Trigrams_clean %>%
filter(
party == "Dem/Ind",
concept %in% top_concepts_by_party$concept[
top_concepts_by_party$party == "Dem/Ind"
]
) %>%
count(WeekStart, concept, name = "weekly_count") %>%
group_by(concept) %>%
mutate(total_mentions = sum(weekly_count)) %>%
ungroup() %>%
arrange(desc(total_mentions)) %>%
mutate(
facet_label = paste0(
concept,
" (", format(total_mentions, big.mark = ","), " mentions)"
),
facet_label = factor(facet_label, levels = unique(facet_label))
)
############################################################
# STEP 6: Democratic / Independent small-multiple line chart
############################################################
dem_plot <- ggplot(
dem_weekly,
aes(
x = WeekStart,
y = weekly_count,
group = facet_label,
linewidth = total_mentions
)
) +
geom_line(color = "#08519c") +
geom_point(color = "#08519c", size = 2.8) +
facet_wrap(
~ facet_label,
ncol = 2,
scales = "free_y",
labeller = labeller(
facet_label = function(x) str_wrap(x, width = 28)
)
) +
scale_linewidth(
range = c(0.6, 1.8),
guide = "none"
) +
labs(
title = "Weekly Volume of Core Trigram Concepts — Democrats & Independents",
x = "Week",
y = "Weekly mentions"
) +
theme_bw(base_size = 12) +
theme(
strip.text = element_text(
size = 10.5,
face = "bold",
lineheight = 1.05
),
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
panel.spacing = unit(1.2, "lines")
)
print(dem_plot)