This code uses the Media Cloud API to collect news story counts for two topics, Artificial Intelligence and Immigration, over a specified time period. It downloads daily story counts, combines the results into a single dataset, and then groups the data by week to calculate the total number of stories published each week for each topic. The code also creates summary statistics, including the total number of stories, weekly minimum, weekly maximum, and average weekly coverage for each topic.
This interactive Plotly line graph visualizes how media coverage of Artificial Intelligence and Immigration changes over time. Each point on the graph represents the total number of stories published during a particular week, while the lines show overall trends in coverage throughout the year. By comparing the two lines, we identify which topic received more media attention, when coverage peaked, and how interest in each topic increased or decreased across different weeks.
if (!require("plotly")) install.packages("plotly")
library(plotly)
############################################################
# STEP 1: Install and Load Packages
############################################################
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("httr2")) install.packages("httr2")
if (!require("lubridate")) install.packages("lubridate")
if (!require("kableExtra")) install.packages("kableExtra")
if (!require("plotly")) install.packages("plotly")
library(tidyverse)
library(httr2)
library(lubridate)
library(kableExtra)
library(plotly)
############################################################
# STEP 2: Verify Media Cloud API Key
############################################################
if (!nzchar(Sys.getenv("MEDIACLOUD_KEY"))) {
stop(
"No Media Cloud API key was found.\n",
"Please save your key to .Renviron first."
)
}
############################################################
# STEP 3: Define Two Topics
############################################################
topics <- c(
"Artificial Intelligence" = "\"artificial intelligence\"",
"Immigration" = "\"immigration\""
)
############################################################
# STEP 4: Define the Date Range
############################################################
start_date <- "2026-01-01"
end_date <- "2026-09-01"
############################################################
# STEP 5: Create Function to Download Daily Counts
############################################################
get_counts <- function(query) {
Sys.sleep(35)
response <-
request(
"https://search.mediacloud.org/api/search/count-over-time"
) |>
req_headers(
Authorization = paste(
"Token",
Sys.getenv("MEDIACLOUD_KEY")
)
) |>
req_url_query(
q = query,
start = start_date,
end = end_date,
platform = "onlinenews-mediacloud",
cs = 34412234
) |>
req_perform()
results <-
response |>
resp_body_json()
map_dfr(
results$count_over_time$counts,
as_tibble
) |>
mutate(
date = as.Date(date)
)
}
############################################################
# STEP 6: Download Data
############################################################
topic_data <-
imap_dfr(
topics,
function(search_query, topic_name) {
message("Downloading: ", topic_name)
get_counts(search_query) |>
mutate(
topic = topic_name
)
}
)
############################################################
# STEP 7: Examine Data
############################################################
head(topic_data)
glimpse(topic_data)
############################################################
# STEP 8: Calculate Weekly Story Counts
############################################################
weekly_counts <-
topic_data |>
mutate(
week = floor_date(date, unit = "week")
) |>
group_by(topic, week) |>
summarise(
stories = sum(count),
.groups = "drop"
)
############################################################
# STEP 9: Weekly Counts Table
############################################################
Weekly_Table <-
weekly_counts |>
arrange(topic, week) |>
kbl(
caption = "Weekly Media Cloud Story Counts"
) |>
kable_styling(
full_width = FALSE,
bootstrap_options = c(
"striped",
"hover"
)
)
Weekly_Table
############################################################
# STEP 10: Coverage Summary
############################################################
topic_summary <-
weekly_counts |>
group_by(topic) |>
summarise(
Total_Stories = sum(stories),
Weekly_Minimum = min(stories),
Weekly_Maximum = max(stories),
Weekly_Mean = round(mean(stories), 2),
.groups = "drop"
) |>
arrange(desc(Total_Stories))
Summary_Table <-
topic_summary |>
kbl(
caption = "Coverage Summary by Topic"
) |>
kable_styling(
full_width = FALSE,
bootstrap_options = c(
"striped",
"hover"
)
)
Summary_Table
############################################################
# STEP 11: Interactive Plotly Line Graph
############################################################
Plotly_Line <-
plot_ly(
data = weekly_counts,
x = ~week,
y = ~stories,
color = ~topic,
colors = c("#1f77b4", "#d62728"),
type = "scatter",
mode = "lines+markers",
text = ~paste(
"Topic:", topic,
"<br>Week:", week,
"<br>Stories:", stories
),
hoverinfo = "text"
) |>
layout(
title = list(
text = "Weekly Media Coverage Volume"
),
xaxis = list(
title = "Week"
),
yaxis = list(
title = "Number of Stories"
),
legend = list(
title = list(text = "Topic")
),
hovermode = "x unified"
)
Plotly_Line
############################################################
# STEP 12: Save Data
############################################################
write_csv(
weekly_counts,
"weekly_story_counts.csv"
)