The graph shows that both NASA and SpaceX maintained a regular presence in news coverage throughout 2026. While NASA’s coverage remained relatively stable, SpaceX experienced several major peaks, suggesting that media attention surrounding the company was driven by specific events.

The noticeable NASA spike at the end of March and beginning of April likely reflects extensive coverage of the Artemis II mission around the moon which generated substantial media attention. The significant SpaceX peak during the week of June 7 likely corresponds to news about the compaby “going public” with its initial public offering (IPO), which valued SpaceX at approximately $1.77 trillion and became the largest IPO in history.

Despite public interest in space exploration, overall coverage levels were much lower than those seen for other major topics such as artificial intelligence, which can indicate that space-related stories occupy a smaller portion of the news cycle.

Code:

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

# Replace the topic labels and search queries below.
#
# Examples:
# "artificial intelligence"
# "climate change"
# "immigration"
# "inflation"

topics <- c(
  "SpaceX" = "SpaceX",
  "NASA" = "NASA"
)
############################################################
# STEP 4: Define the Date Range
############################################################

start_date <- "2026-01-04"
end_date <- "2026-09-20"

############################################################
# 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: Download Data for Both Topics
############################################################

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 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"
  )
weekly_table <- weekly_counts |>
  arrange(topic, week) |>
  kbl(
    caption = "Weekly Media Cloud Story Counts"
  ) |>
  kable_styling(
    full_width = FALSE,
    bootstrap_options = c(
      "striped",
      "hover"
    )
  )
############################################################
# STEP 9: Display Weekly Counts
############################################################

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: 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)) |>
  kbl(
    caption = "Coverage Summary by Topic"
  ) |>
  kable_styling(
    full_width = FALSE,
    bootstrap_options = c(
      "striped",
      "hover"
    )
  )

############################################################
# STEP 11: Create Interactive Plotly Line Graph
############################################################

weekly_plotly <- plot_ly(
  data = weekly_counts,
  x = ~week,
  y = ~stories,
  color = ~topic,
  colors = "Set1",
  type = "scatter",
  mode = "lines+markers",
  marker = list(size = 5),
  line = list(width = 2),
  customdata = ~format(stories, big.mark = ","),
  hovertemplate = paste(
    "<b>Topic:</b> %{fullData.name}<br>",
    "<b>Week:</b> %{x}<br>",
    "<b>Stories:</b> %{customdata}<extra></extra>"
  )
) |>
  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"
  )

weekly_plotly

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

write_csv(
  weekly_counts,
  "weekly_story_counts.csv"
)
weekly_plotly