The results from this chart show that Immigration received the highest overall number of stories, while Artificial Intelligence received fewer studies between January 4th, 2026 and September 5th, 2026. The fluctuations on the graph show how media organizations prioritize certain issues at different times. The findings provide insight into which topic attracted more attention in online news media and how that attention has changed over time.

Here is a look at the content:

Code:

############################################################
# 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 <- "2025-12-01"
end_date <- "2026-09-01"

############################################################
# STEP 5: Create a Function to Download
# Daily Story Counts
############################################################

get_counts <- function(query) {

  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: Load Previously Downloaded Data
############################################################

topic_data <- read_csv("topic_data.csv")

############################################################
# STEP 7: Examine the Downloaded 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: Display Weekly Counts
############################################################

weekly_counts |>
  arrange(topic, week) |>
  kbl(
    caption = "Weekly Media Cloud Story Counts"
  ) |>
  kable_styling(
    full_width = FALSE,
    bootstrap_options = c(
      "striped",
      "hover"
    )
  )

############################################################
# STEP 10: Summarize Total Coverage
############################################################

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))

topic_summary |>
  kbl(
    caption = "Coverage Summary by Topic"
  ) |>
  kable_styling(
    full_width = FALSE,
    bootstrap_options = c(
      "striped",
      "hover"
    )
  )

############################################################
# STEP 11: Create a Static Line Graph
############################################################

weekly_counts |>
  ggplot(
    aes(
      x = week,
      y = stories,
      color = topic
    )
  ) +
  geom_line(
    linewidth = 1
  ) +
  geom_point(
    size = 2
  ) +
  labs(
    title = "Weekly Media Coverage Volume",
    subtitle = "Comparison of Two Topics",
    x = "Week",
    y = "Number of Stories",
    color = "Topic"
  ) +
  theme_minimal()

############################################################
# STEP 12: Create Interactive Plotly Line Chart
############################################################

Plotly_LineChart <-
  plot_ly(
    data = weekly_counts,
    x = ~week,
    y = ~stories,
    color = ~topic,
    colors = "Set1",
    type = "scatter",
    mode = "lines+markers",
    customdata = ~topic,
    hovertemplate = paste(
      "<b>Topic:</b> %{customdata}<br>",
      "<b>Stories:</b> %{y:,}<br>",
      "<b>Week:</b> %{x|%b %d, %Y}",
      "<extra></extra>"
    )
  ) |>
  layout(
    title = list(
      text = "Weekly Media Coverage Volume"
    ),
    xaxis = list(
      title = "Week"
    ),
    yaxis = list(
      title = "Number of Stories",
      separatethousands = TRUE
    ),
    hovermode = "x unified",
    legend = list(
      title = list(
        text = "Topic"
      )
    )
  )

Plotly_LineChart

############################################################
# STEP 13: Save Results as a CSV File
############################################################

write_csv(
  weekly_counts,
  "weekly_story_counts.csv"
)