Enhancing GDP Visualizations Through Interactivity

For this project, I transformed my previous U.S. GDP data visualization (from portfolio1) by incorporating interactivity with the plotly and DT packages. The original version of the project included static ggplot charts that presented GDP trends and business-cycle dynamics. While these visualizations effectively communicated broad patterns, they lacked the ability for users to explore specific time periods, compare exact values, or interactively engage with the data.

To address this, I added two interactive components. First, I used plotly to convert the static line chart of real GDP levels into an interactive chart. Users can now hover over data points to view precise GDP values and dates, zoom into periods of interest (such as during recessions), and pan across the full historical range. Second, I transformed the year-over-year GDP growth bar chart into an interactive plot using plotly, allowing exploration of growth rates over time.

The original chart and dataset can be found here: https://fred.stlouisfed.org/series/GDPC1

# 1) Load & prepare GDP data
gdp <- read_csv("GDPC1.csv", col_types = cols()) %>%
  rename(date = observation_date, gdp = GDPC1) %>%
  mutate(date = ymd(date))

# 2) Hard-code NBER recessions
recessions <- tribble(
  ~start,       ~end,
  "1948-11-01","1949-10-01",
  "1953-07-01","1954-05-01",
  "1957-08-01","1958-04-01",
  "1960-04-01","1961-02-01",
  "1969-12-01","1970-11-01",
  "1973-11-01","1975-03-01",
  "1980-01-01","1980-07-01",
  "1981-07-01","1982-11-01",
  "1990-07-01","1991-03-01",
  "2001-03-01","2001-11-01",
  "2007-12-01","2009-06-01",
  "2020-02-01","2020-04-01"
) %>% 
  mutate(across(everything(), ymd))

# 3) Build the plot
gdp_line <- ggplot() +
  # recession bars
  geom_rect(
    data    = recessions,
    aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf),
    fill    = "grey80", alpha = 0.5
  ) +
  # GDP line + legend
  geom_line(
    data      = gdp,
    aes(x = date, y = gdp, color = "Real Gross Domestic Product"),
    linewidth = 1
  ) +
  scale_color_manual(
    name   = NULL,
    values = "navy"
  ) +
  guides(
    color = guide_legend(
      override.aes = list(linewidth = 1.5),
      direction    = "horizontal"
    )
  ) +
  # x axis every 5 years
  scale_x_date(
    breaks      = seq(ymd("1950-01-01"), ymd("2020-01-01"), by = "5 years"),
    date_labels = "%Y",
    expand      = c(0, 0)
  ) +
  # y axis 0–24000 by 4000
  scale_y_continuous(
    breaks = seq(0, 24000, by = 4000),
    labels = scales::comma,
    limits = c(0, 24000),
    expand = c(0, 0)
  ) +
  # titles & caption
  labs(
    title   = "Real Gross Domestic Product",
    y       = "Billions of Chained 2017 Dollars",
    caption = paste(
      "Source: U.S. Bureau of Economic Analysis via FRED®",
      "Shaded areas indicate U.S. recessions.",
      "fred.stlouisfed.org",
      sep = "\n"
    )
  ) +
  # minimal theme + solid horizontal grid lines
  theme_minimal(base_size = 11) +
 theme(
    legend.position    = "top",
    panel.grid.major.x = element_blank(),
    panel.grid.minor   = element_blank(),
    panel.grid.major.y = element_line(color = "grey90", size = 0.5),
    plot.title         = element_text(face = "bold", size = 14, hjust = 0)
  ) +
  coord_cartesian(clip = "off")

ggplotly(gdp_line) 

Second graph:

# Data prep
gdp <- read_csv("GDPC1.csv", col_types = cols()) %>%
  rename(date = observation_date, gdp = GDPC1) %>%
  mutate(date = as_date(date))

gdp_growth <- gdp %>%
  arrange(date) %>%
  mutate(yoy = (gdp / lag(gdp, 4) - 1) * 100) %>%
  drop_na() %>%
  # create a factor with exactly the two levels in the right order
  mutate(
    growth = factor(
      if_else(yoy > 0, "Positive", "Negative"),
      levels = c("Negative", "Positive")
    )
  )

recessions <- tribble(
  ~start,       ~end,
  "1948-11-01","1949-10-01",
  "1953-07-01","1954-05-01",
  "1957-08-01","1958-04-01",
  "1960-04-01","1961-02-01",
  "1969-12-01","1970-11-01",
  "1973-11-01","1975-03-01",
  "1980-01-01","1980-07-01",
  "1981-07-01","1982-11-01",
  "1990-07-01","1991-03-01",
  "2001-03-01","2001-11-01",
  "2007-12-01","2009-06-01",
  "2020-02-01","2020-04-01"
) %>% mutate(across(everything(), ymd))

# Plot
gdp_growth_chart <- ggplot() +
  geom_rect(
    data = recessions,
    aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf),
    fill = "grey80", alpha = .5
  ) +
  geom_col(
    data = gdp_growth,
    aes(x = date, y = yoy, fill = growth),
    width = 90
  ) +
  geom_hline(yintercept = 0, color = "grey50") +
  scale_x_date(
    breaks      = seq(as.Date("1950-01-01"), as.Date("2020-01-01"), by = "5 years"),
    date_labels = "%Y",
    expand      = c(0, 0)
  ) +
  scale_y_continuous(
    breaks = seq(-10, 12, by = 2),
    labels = function(x) paste0(x, "%"),
    expand = expansion(mult = c(0, .02))
  ) +
  scale_fill_manual(
    name   = "Growth",
    values = c(
      "Negative" = "red",
      "Positive" = "springgreen2"
    )
  ) +
  labs(
    title    = "Year-over-Year Growth in Real GDP",
    subtitle = "Bars show annual % change; shaded areas are NBER recessions",
    x        = NULL,
    y        = "GDP Growth (percent)",
    caption  = "Source: BEA via FRED®"
  ) +
  theme_minimal(base_size = 11) +
  theme(
    legend.position = "bottom"
  )

ggplotly(gdp_growth_chart)

References