This expanded second-level agenda-setting code allows you to plot
volume for the overall topic as well as two attributes of the topic. For
example, here’s volume for “Education” (See Topic1_phrases
/ blue line), and the attributes “Money” (See
Topic2_phrases / green line) and “Violence” (See
Topic3_phrases / green line).
Code:
# ============================================
# APNews text analysis (Second-level agenda-setting theory version)
# ============================================
# ============================================
# --- Load required libraries ---
# ============================================
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("tidytext")) install.packages("tidytext")
if (!require("plotly")) install.packages("plotly")
library(tidyverse)
library(tidytext)
library(plotly)
# ============================================
# --- Define Custom Topic Labels ---
# ============================================
# You can change these labels to anything you want.
# They will appear in the chart legend and title.
topic_labels <- list(
Topic1 = "All education",
Topic2 = "Violence",
Topic3 = "Money"
)
# ============================================
# --- Load the APNews data ---
# ============================================
FetchedData <- readRDS(url("https://github.com/drkblake/Data/raw/refs/heads/main/APNews.rds"))
saveRDS(FetchedData, file = "APNews.rds")
rm(FetchedData)
APNews <- readRDS("APNews.rds")
# ============================================
# --- Define and apply FilterTopic ---
# ============================================
FilterTopic_phrases <- c(
"education", "educational", "educator", "educators",
"school", "schools", "classroom", "classrooms",
"teacher", "teachers"
)
escaped_FilterTopic <- str_replace_all(
FilterTopic_phrases,
"([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
)
FilterTopic_pattern <- paste0("\\b", escaped_FilterTopic, "\\b", collapse = "|")
APNews <- APNews %>%
mutate(
Full.Text.clean = str_squish(Full.Text),
FilterTopic = if_else(
str_detect(Full.Text.clean, regex(FilterTopic_pattern, ignore_case = TRUE)),
"Yes", "No"
)
)
TopicNews <- APNews %>% filter(FilterTopic == "Yes")
# ============================================
# --- Define Topic1 (Education) ---
# ============================================
Topic1_phrases <- c(
"education", "educational", "educator", "educators",
"school", "schools", "classroom", "classrooms",
"teacher", "teachers"
)
Topic1_pattern <- paste0("\\b", str_replace_all(Topic1_phrases,
"([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
), "\\b", collapse = "|")
TopicNews <- TopicNews %>%
mutate(
Topic1 = if_else(
str_detect(Full.Text.clean, regex(Topic1_pattern, ignore_case = TRUE)),
"Yes", "No"
)
)
# ============================================
# --- Define Topic2 (Shootings) ---
# ============================================
Topic2_phrases <- c(
"shoot", "shooting", "shooter", "shot",
"gun", "rifle", "weapon", "kill", "killed"
)
Topic2_pattern <- paste0("\\b", str_replace_all(Topic2_phrases,
"([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
), "\\b", collapse = "|")
TopicNews <- TopicNews %>%
mutate(
Topic2 = if_else(
str_detect(Full.Text.clean, regex(Topic2_pattern, ignore_case = TRUE)),
"Yes", "No"
)
)
# ============================================
# --- Define Topic3 (Economy) ---
# ============================================
Topic3_phrases <- c(
"fund", "funds", "funding",
"grant", "grants", "pay",
"salary", "salaries", "service",
"services", "lunch", "lunches",
"special education"
)
Topic3_pattern <- paste0("\\b", str_replace_all(Topic3_phrases,
"([\\^$.|?*+()\\[\\]{}\\\\])", "\\\\\\1"
), "\\b", collapse = "|")
TopicNews <- TopicNews %>%
mutate(
Topic3 = if_else(
str_detect(Full.Text.clean, regex(Topic3_pattern, ignore_case = TRUE)),
"Yes", "No"
)
)
# ============================================
# --- Summarize weekly counts for all topics ---
# ============================================
Topic1_weekly <- TopicNews %>%
filter(Topic1 == "Yes") %>%
group_by(Week) %>%
summarize(Count = n(), .groups = "drop") %>%
mutate(Topic = topic_labels$Topic1)
Topic2_weekly <- TopicNews %>%
filter(Topic2 == "Yes") %>%
group_by(Week) %>%
summarize(Count = n(), .groups = "drop") %>%
mutate(Topic = topic_labels$Topic2)
Topic3_weekly <- TopicNews %>%
filter(Topic3 == "Yes") %>%
group_by(Week) %>%
summarize(Count = n(), .groups = "drop") %>%
mutate(Topic = topic_labels$Topic3)
Weekly_counts <- bind_rows(Topic1_weekly, Topic2_weekly, Topic3_weekly) %>%
tidyr::complete(
Topic,
Week = full_seq(range(Week), 1),
fill = list(Count = 0)
) %>%
arrange(Topic, Week)
# ============================================
# --- Visualize the results ---
# ============================================
AS2 <- plot_ly(
data = Weekly_counts,
x = ~Week,
y = ~Count,
color = ~Topic,
colors = c("steelblue", "seagreen", "firebrick"),
type = "scatter",
mode = "lines+markers",
line = list(width = 2),
marker = list(size = 6)
) %>%
layout(
title = paste(
"Weekly Counts of",
paste(unlist(topic_labels), collapse = ", "),
"Stories (Filtered Dataset)"
),
xaxis = list(title = "Week Number (starting with Week 1 of 2025)", dtick = 1),
yaxis = list(title = "Number of Articles"),
legend = list(title = list(text = "Topic")),
hovermode = "x unified"
)
# ============================================
# --- Display the chart ---
# ============================================
AS2