Introduction

To understand the dynamics of the U.S. economy, it is essential to consider both national and localized perspectives. This analysis develops a diffusion index by incorporating employment, industrial production, and consumer sentiment data. The resulting index is then compared with the Chicago Fed National Activity Diffusion Index (CFNAIDIFF), offering valuable insights into patterns of economic growth and contraction over time.

Data selection and Diffusion Index Construction.

The diffusion index reflects economic expansion and contraction based on pulling data for three selected variables. Here selected variables are Employment, industrial production, and housing starts.

suppressWarnings({
  suppressPackageStartupMessages({
    library(tidyverse)
    library(quantmod)
    library(tsbox)
    library(zoo)
  })
})

options(digits = 3, scipen = 99999)
graphics.off()
# Load economic variables from FRED
getSymbols(c("PAYEMS", "INDPRO", "HOUST"),
           src = "FRED", return.class = 'xts', 
           from = "2010-01-01", to = Sys.Date())
## [1] "PAYEMS" "INDPRO" "HOUST"

Comparison of Custom Diffusion Index and CFNAIDIFF

# Load economic variables
employment <- PAYEMS
industrial_production <- INDPRO
housing  <- HOUST

employment_ss <- employment["2010-01-31/2024-09-01"] |> ts_ts()
industrial_ss <- industrial_production["2010-01-31/2024-09-01"] |> ts_ts()
housing_ss <- housing["2010-01-31/2024-09-01"] |> ts_ts()

mydata <- cbind.data.frame(employment_ss, industrial_ss, housing_ss)

mydf <- mydata %>%
  mutate(
    emp_diff = tsibble::difference(employment_ss, differences = 1),
    ind_diff = tsibble::difference(industrial_ss, differences = 1),
    house_diff = tsibble::difference(housing_ss, differences = 1)
  ) %>%
  dplyr::select(emp_diff, ind_diff, house_diff) %>%
  na.omit()
## Registered S3 method overwritten by 'tsibble':
##   method               from 
##   as_tibble.grouped_df dplyr

Visual Observations (First Plot):

# Construct diffusion index
mydf_mat <- apply(mydf, 2, sign)
pos <- apply(mydf_mat, 1, function(row) sum(row > 0))
neg <- apply(mydf_mat, 1, function(row) sum(row < 0))
tot <- pos + neg
index <- (pos / tot - neg / tot) * 100
ma_index <- rollmean(index, 7, align = "right", na.pad = TRUE)
# Date sequence
Date <- seq.Date(from = as.Date("2010-05-01"), length.out = length(index), by = "month")
diffusion_df <- cbind.data.frame(Date, index, ma_index)
#Plotting the Diffusion Index
ggplot(diffusion_df, aes(x = Date, y = index)) +
  # Line for  diffusion index
  geom_line(color = "yellow", size = 0.8) +
  # Smoothed trend line with transparency
  geom_smooth(color = "blue", fill = "orange", alpha = 0.3, size = 1.2) +
  # Adding labels 
  geom_text(data = diffusion_df[c(1, nrow(diffusion_df)), ],
            aes(label = paste0(round(index, 2), "%")), 
            vjust = -1, size = 3.5, fontface = "bold", color = "pink") +
  # Adding a horizontal reference line
  geom_hline(yintercept = 0, linetype = "dashed", color = "brown", size = 0.8) +
  # Vertical line for a key event (e.g., COVID-19)
  geom_vline(xintercept = as.Date("2020-03-01"), linetype = "dotted", color = "green", size = 1) +
  annotate("text", x = as.Date("2020-03-01"), y = -90, 
           label = "COVID-19", color = "grey", size = 4, hjust = 0, angle = 90) +
  # Title, subtitle, and axis labels
  labs(
    title = "U.S. Economic Diffusion Index Over Time",
    subtitle = "Analyzing economic trends",
    x = "Year",
    y = "Diffusion Index (%)"
  ) +
  # Adjust y-axis limits to zoom out
  scale_y_continuous(limits = c(-120, 120)) +
  # Enhance visual appearance with themes
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(size = 20, face = "bold", hjust = 0.5, color = "black"),
    plot.subtitle = element_text(size = 14, face = "italic", hjust = 0.5, color = "orange"),
    axis.title.x = element_text(size = 14, face = "bold", color = "pink"),
    axis.title.y = element_text(size = 14, face = "bold", color = "brown"),
    axis.text = element_text(size = 12, color = "red"),
    panel.grid.major = element_line(color = "blue", size = 0.5),
    panel.grid.minor = element_blank(),
    legend.position = "none",
    plot.background = element_rect(fill = "grey", color = "yellow")
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The `size` argument of `element_line()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

Long-Term Trend in Diffusion Index

#  Load CFNAIDIFF data from FRED
getSymbols("CFNAIDIFF", src = "FRED", return.class = 'xts', from = "2010-01-01")
## [1] "CFNAIDIFF"
cfnaidiff_ss <- CFNAIDIFF["2010-05-01/2024-09-01"] |> ts_ts()
min_length <- min(length(ma_index), length(cfnaidiff_ss))
ma_index <- ma_index[1:min_length]
cfnaidiff_ss <- cfnaidiff_ss[1:min_length]
Date <- Date[1:min_length]

#The comparison data frame
compare_df <- cbind.data.frame(Date, diffusion_index = ma_index, CFNAIDIFF = cfnaidiff_ss)

correlation <- cor(compare_df$diffusion_index, compare_df$CFNAIDIFF, use = "complete.obs")

# Enhanced comparison plot with interactivity
plotly::ggplotly(
  ggplot() +
    geom_line(data = compare_df, aes(x = Date, y = diffusion_index, color = "Diffusion Index"), size = 1.2) +
    geom_line(data = compare_df, aes(x = Date, y = CFNAIDIFF * 100, color = "CFNAIDIFF"), size = 1.2, linetype = "dashed") +
    scale_color_manual(
      values = c("Diffusion Index" = "orange", "CFNAIDIFF" = "pink")
    ) +
    labs(
      title = "Comparison of Diffusion Index and CFNAIDIFF",
      x = "Year",
      y = "Index Value",
      color = "Legend"
    ) +
    theme_minimal(base_size = 8) +
    theme(
      plot.title = element_text(size = 10, face = "bold", hjust = 0.5),
      legend.position = "bottom"
    )
)

Key Economic Insights

Recent Economic Conditions (Post-September 2024)

Conclusion

The Diffusion Index reflects notable economic fluctuations over time, with recent declines driven by drops in employment, industrial production, and consumer sentiment. In contrast, CFNAIDIFF shows steadier national activity, with less volatility compared to the Diffusion Index. The weak correlation of 0.157 highlights the differences in their focus: the Diffusion Index is more sensitive to localized economic changes, while CFNAIDIFF captures broader national trends. The outlook suggests that the Diffusion Index indicates regional or sectoral weaknesses, whereas CFNAIDIFF points to a stable national economy without widespread contraction.