Rationale

Framing theory explains that journalists do more than select which issues to cover; they also decide how to present those issues. The words and ideas emphasized in coverage can lead audiences to interpret an issue in particular ways, shaping judgments about causes, effects, and policy responses.

One area where framing differences are visible involves U.S. tariff policy. Since President Donald Trump reintroduced tariffs as a signature economic tool, public debate has alternated between portraying them as protective measures that boost the American economy and as burdens that slow growth and raise prices. These contrasting frames mirror the theoretical distinction between gain frames, which stress positive outcomes, and loss frames, which highlight costs and risks.

Drawing on what framing theory predicts about the power of such interpretive choices, this project will compare how APNews.com coverage presents tariffs across two competing frames: one depicting tariffs as an economic boost and the other portraying them as an economic burden. Specifically, the analysis will compare the number of APNews.com stories per week that include language associated with each frame between Jan. 1 and Oct. 15, 2025.

The results will add to the theoretical understanding of how a single economic policy can be defined in sharply different ways, either as patriotic protectionism or as costly trade conflict, and how those definitions fluctuate over time in major news coverage.

Hypothesis

Weekly APNews.com coverage of tariffs will differ in the frequency of words and phrases associated with the economic boost and economic burden frames during the first ten months of 2025.

Variables & method

The dependent variable in this analysis is the weekly APNews.com coverage volume for tariff-related stories. It is measured continuously as the number of APNews.com stories per week that contained at least one keyword associated with a specific frame.

The independent variable is frame type, measured categorically as either Economic Boost or Economic Burden.

The analysis began by filtering all APNews.com stories published between Jan. 1 and Oct. 15, 2025 to include only those referencing tariffs or related terms (e.g., tariff, tariffs, import duty, trade tariff, steel tariff, foreign goods). This filtering produced a subset of tariff-related stories.

Within that subset, stories were categorized based on the presence of keywords corresponding to two contrasting frames.

The results were visualized in a line graph showing the relative prominence of the Economic Boost and Economic Burden frames over time. Later analyses may use a paired-samples t-test to assess whether observed differences in weekly frame volume are statistically significant.

Results & discussion

The figure below shows the weekly volume of APNews.com coverage that used Economic Boost and Economic Burden language in stories about tariffs between January and mid-October 2025.

It is not surprising that the Economic Burden frame appeared more consistently and frequently throughout the coverage period. Words and phrases linked to this frame such as trade war, inflation, and cost to consumers were dominant in reporting during most weeks. The persistence of these terms suggests that APNews.com largely emphasized the negative financial and trade consequences associated with tariff policy rather than its intended benefits.

In contrast, the Economic Boost frame appeared only at certain times. A noticeable spike occurred shortly after the administration’s tariff announcement in April, when government officials and industry advocates promoted tariffs as measures to protect American manufacturing and strengthen the United States economy. This period of positive framing lasted for several weeks but quickly declined as stories about retaliatory trade actions, higher consumer prices, and market uncertainty became more prominent in coverage.

Overall, the pattern shows that APNews.com framed tariffs primarily as an economic burden rather than an economic boost. The short burst of optimistic framing that followed the initial announcement was outweighed by sustained reporting that highlighted the economic strain and international response tied to tariff policies. These findings support framing theory’s idea that media coverage influences public understanding of economic issues through emphasis and interpretation rather than through simple topic selection.

Code:

# ============================================
# APNews text analysis (Framing Theory version)
# ============================================

# ============================================
# --- Load required libraries ---
# ============================================

if (!require("tidyverse")) install.packages("tidyverse")
if (!require("tidytext")) install.packages("tidytext")

library(tidyverse)
library(tidytext)

# ============================================
# --- Load the APNews data ---
# ============================================

# Read the data from the web
FetchedData <- readRDS(url("https://github.com/drkblake/Data/raw/refs/heads/main/APNews.rds"))
# Save the data on your computer
saveRDS(FetchedData, file = "APNews.rds")
# remove the downloaded data from the environment
rm (FetchedData)

APNews <- readRDS("APNews.rds")

# ============================================
# --- Define and apply FilterTopic ---
# ============================================

# --- Define FilterTopic phrases ---
FilterTopic_phrases <- c(
  "tariff",
  "tariffs",
  "import duty",
  "import duties",
  "trade tariff",
  "steel tariff",
  "aluminum tariff",
  "foreign goods"
)

# --- Escape regex special characters ---
escaped_FilterTopic <- str_replace_all(
  FilterTopic_phrases,
  "([\\^$.|?*+()\\[\\]{}\\\\])",
  "\\\\\\1"
)

# --- Build whole-word/phrase regex pattern ---
FilterTopic_pattern <- paste0("\\b", escaped_FilterTopic, "\\b", collapse = "|")

# --- Flag stories matching the FilterTopic ---
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"
    )
  )

# --- Create a TopicNews data frame consisting only of FilterTopic stories ---
TopicNews <- APNews %>%
  filter(FilterTopic == "Yes")

# ============================================
# --- Flag Topic1-related stories (within TopicNews) ---
# ============================================

# --- Define Topic1 phrases ---
phrases <- c(
  "local business",
  "economic growth",
  "Strong U.S. Economy",
  "local businessess",
  "fair trade",
  "boost U.S. economy",
  "strengthen economy",
  "made in America",
  "creating jobs",
  "increase production"
  
)

# --- Escape regex special characters ---
escaped_phrases <- str_replace_all(
  phrases,
  "([\\^$.|?*+()\\[\\]{}\\\\])",
  "\\\\\\1"
)

# --- Build pattern and apply matching ---
pattern <- paste0("\\b", escaped_phrases, "\\b", collapse = "|")

TopicNews <- TopicNews %>%
  mutate(
    Topic1 = if_else(
      str_detect(Full.Text.clean, regex(pattern, ignore_case = TRUE)),
      "Yes",
      "No"
    )
  )

# ============================================
# --- Flag Topic2-related stories (within TopicNews) ---
# ============================================

# --- Define Topic2 phrases ---
phrases <- c(
  "trade war",
  "inflation",
  "cost to consumers",
  "economic strain",
  "export losses",
  "supply chain disruption",
  "import cost"
)

# --- Escape regex special characters ---
escaped_phrases <- str_replace_all(
  phrases,
  "([\\^$.|?*+()\\[\\]{}\\\\])",
  "\\\\\\1"
)

# --- Build pattern and apply matching ---
pattern <- paste0("\\b", escaped_phrases, "\\b", collapse = "|")

TopicNews <- TopicNews %>%
  mutate(
    Topic2 = if_else(
      str_detect(Full.Text.clean, regex(pattern, ignore_case = TRUE)),
      "Yes",
      "No"
    )
  )

# ============================================
# --- Visualize weekly counts of Topic1- and Topic2-related stories ---
# ============================================

if (!require("plotly")) install.packages("plotly")
library(plotly)

# --- Summarize weekly counts for Topic1 = "Yes" ---
Topic1_weekly <- TopicNews %>%
  filter(Topic1 == "Yes") %>%
  group_by(Week) %>%
  summarize(Count = n(), .groups = "drop") %>%
  mutate(Topic = "Economic Boost") # Note custom Topic1 label

# --- Summarize weekly counts for Topic2 = "Yes" ---
Topic2_weekly <- TopicNews %>%
  filter(Topic2 == "Yes") %>%
  group_by(Week) %>%
  summarize(Count = n(), .groups = "drop") %>%
  mutate(Topic = "Economic Burden") # Note custom Topic2 label

# --- Combine both summaries into one data frame ---
Weekly_counts <- bind_rows(Topic2_weekly, Topic1_weekly)

# --- Fill in missing combinations with zero counts ---
Weekly_counts <- Weekly_counts %>%
  tidyr::complete(
    Topic,
    Week = full_seq(range(Week), 1),  # generate all week numbers
    fill = list(Count = 0)
  ) %>%
  arrange(Topic, Week)

# --- Create interactive plotly line chart ---
FR1 <- plot_ly(
  data = Weekly_counts,
  x = ~Week,
  y = ~Count,
  color = ~Topic,
  colors = c("steelblue", "firebrick"),
  type = "scatter",
  mode = "lines+markers",
  line = list(width = 2),
  marker = list(size = 6)
) %>%
  layout(
    title = "Weekly Counts of Topic1- and Topic2-Related Stories within the FilterTopic 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"
  )

# ============================================
# --- Show the chart ---
# ============================================

FR1