---
title: "Where Does $7 Trillion Go?"
subtitle: "U.S. federal outlays, FY2025 — 100 squares represent about $7.0T (≈ $70B each). Total spending: $7.0T | Deficit: $1.8T"
description: "A waffle chart breaking down U.S. federal outlays for fiscal year 2025 into 100 equal squares, each representing approximately $70 billion of the $7.0 trillion total. Social Security, Medicare, and Net Interest alone account for nearly half of all spending, while the federal deficit reached $1.8 trillion — the largest categories visualized through a part-to-whole composition. Built with ggplot2 in R using CBO data."
date: "2026-04-01"
author:
- name: "Steven Ponce"
url: "https://stevenponce.netlify.app"
citation:
url: "https://stevenponce.netlify.app/data_visualizations/30DayChartChallenge/2026/30dcc_2026_01.html"
categories: ["30DayChartChallenge", "2026"]
tags: [
"30DayChartChallenge",
"Part-to-Whole",
"Waffle Chart",
"Federal Budget",
"Fiscal Policy",
"United States",
"CBO",
"Government Spending",
"ggplot2",
"Comparisons"
]
image: "thumbnails/30dcc_2026_01.png"
format:
html:
toc: true
toc-depth: 5
code-link: true
code-fold: true
code-tools: true
code-summary: "Show code"
editor_options:
chunk_output_type: inline
execute:
freeze: true
cache: true
error: false
message: false
warning: false
eval: true
---
{#fig-1}
### [**Steps to Create this Graphic**]{.mark}
#### [1. Load Packages & Setup]{.smallcaps}
```{r}
#| label: load
#| warning: false
#| message: false
#| results: "hide"
## 1. LOAD PACKAGES & SETUP ----
suppressPackageStartupMessages({
pacman::p_load(
tidyverse, ggtext, showtext,
janitor, scales, glue
)
})
### |- figure size ----
camcorder::gg_record(
dir = here::here("temp_plots"),
device = "png",
width = 7,
height = 6,
units = "in",
dpi = 320
)
# Source utility functions
suppressMessages(source(here::here("R/utils/fonts.R")))
source(here::here("R/utils/social_icons.R"))
source(here::here("R/utils/image_utils.R"))
source(here::here("R/themes/base_theme.R"))
```
#### [2. Read in the Data]{.smallcaps}
```{r}
#| label: read
#| include: true
#| eval: true
#| warning: false
# FY2025 actual federal outlays (billions USD)
# Source: CBO Monthly Budget Review, October 2025 (fiscal year end)
# Total outlays: ~$7.0 trillion | Deficit: $1.8 trillion
#
# Key verified figures (CBO + CRFB reconciliation):
# Social Security: FY2024 $1,439B + $121B increase = ~$1,560B
# Medicare: FY2024 ~$973B + $117B increase = ~$1,090B (net of offsetting receipts)
# Net Interest: Surpassed $1T for first time; FY2024 ~$970B + $80B = ~$1,050B
# Defense: FY2024 ~$895B + $38B increase = ~$933B
# Medicaid: FY2024 ~$596B + $52B increase = ~$648B
# Veterans Affairs:FY2024 ~$284B + $41B increase = ~$325B
# Other Mandatory + Other Discretionary: residual to $7,000B total
# Residual = 7000 - (1560+1090+1050+933+648+325) = ~$1,394B split below
spending_raw <- tibble(
category = c(
"Social Security",
"Medicare",
"Net Interest",
"Defense",
"Medicaid",
"Other Mandatory",
"Other Discretionary",
"Veterans Affairs"
),
billions = c(1560, 1090, 1050, 933, 648, 747, 647, 325)
)
```
#### [3. Examine the Data]{.smallcaps}
```{r}
#| label: examine
#| include: true
#| eval: true
#| results: 'hide'
#| warning: false
glimpse(spending_raw)
```
#### [4. Tidy Data]{.smallcaps}
```{r}
#| label: tidy
#| warning: false
spending <- spending_raw |>
mutate(
# Calculate percentage share of total
pct = billions / sum(billions),
pct_label = percent(pct, accuracy = 0.1),
# Waffle units: 1 unit = ~$70B (so 100 squares = ~$7T)
units = round(billions / 70),
# Spending type — for secondary grouping / color logic
type = case_when(
category %in% c("Social Security", "Medicare", "Medicaid", "Other Mandatory") ~ "Mandatory",
category == "Net Interest" ~ "Net Interest",
category %in% c("Defense", "Veterans Affairs", "Other Discretionary") ~ "Discretionary"
),
category = factor(category, levels = c(
"Social Security",
"Medicare",
"Net Interest",
"Other Mandatory",
"Medicaid",
"Defense",
"Other Discretionary",
"Veterans Affairs"
))
)
# Expand for waffle — each row = one square
waffle_data <- spending |>
arrange(desc(billions)) |>
uncount(units) |>
mutate(
row_id = row_number(),
x = (row_id - 1) %% 10 + 1,
y = 10 - ((row_id - 1) %/% 10)
)
# Total squares
total_squares <- sum(spending$units) # ~100
### |- legend labels ----
legend_labels <- spending |>
arrange(category) |>
mutate(
label = glue("{category} ${scales::comma(billions)}B")
) |>
pull(label, name = category)
```
#### [5. Visualization Parameters]{.smallcaps}
```{r}
#| label: params
#| include: true
#| warning: false
### |- plot aesthetics ----
colors <- get_theme_colors(
palette = c(
"Social Security" = "#2F6C8E",
"Medicare" = "#4B9FC0",
"Net Interest" = "#D97941",
"Defense" = "#4A6FA5",
"Medicaid" = "#76B8C8",
"Other Mandatory" = "#9CC9D5",
"Other Discretionary" = "#B98AA0",
"Veterans Affairs" = "#9A5874"
)
)
### |- titles and caption ----
title_text <- str_glue("Where Does $7 Trillion Go?")
subtitle_text <- str_glue(
"U.S. federal outlays, FY2025 — {total_squares} squares represent about $7.0T (≈ $70B each)<br>",
"Total spending: **$7.0T** | Deficit: **$1.8T** | Source: **CBO**"
)
caption_text <- create_dcc_caption(
dcc_year = 2026,
dcc_day = 01,
source_text = "Congressional Budget Office (CBO), Monthly Budget Review FY2025"
)
### |- fonts ----
setup_fonts()
fonts <- get_font_families()
### |- plot theme ----
base_theme <- create_base_theme(colors)
weekly_theme <- extend_weekly_theme(
base_theme,
theme(
# Axes
axis.text = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank(),
# Grid — none needed for waffle
panel.grid = element_blank(),
# Legend
legend.position = "right",
legend.direction = "vertical",
legend.title = element_text(
size = 9, face = "bold", family = fonts$text, color = colors$text
),
legend.text = element_text(
size = 8, family = fonts$text, color = colors$text
),
legend.key.size = unit(0.9, "lines"),
legend.key.spacing.y = unit(2, "pt"),
plot.margin = margin(20, 20, 16, 20)
)
)
theme_set(weekly_theme)
```
#### [6. Plot]{.smallcaps}
```{r}
#| label: plot
#| warning: false
### |- main plot ----
p <-
ggplot(waffle_data, aes(x = x, y = y, fill = category)) +
# Geoms
geom_tile(
color = "white",
linewidth = 0.5,
width = 0.92,
height = 0.92
) +
# Scales
scale_fill_manual(
values = unlist(colors$palette),
labels = legend_labels,
name = NULL
) +
# Scales
scale_x_continuous(expand = expansion(add = 0.5)) +
scale_y_continuous(expand = expansion(add = 0.5)) +
coord_equal() +
# Labs
labs(
title = title_text,
subtitle = subtitle_text,
caption = caption_text
) +
# Theme
theme(
plot.title = element_text(
size = rel(1.75),
family = fonts$title,
face = "bold",
color = colors$title,
margin = margin(t = 5, b = 5)
),
plot.subtitle = element_markdown(
size = rel(0.75),
family = fonts$subtitle,
color = colors$subtitle,
lineheight = 1.1,
margin = margin(t = 5, b = 5)
),
plot.caption = element_markdown(
size = rel(0.5),
family = fonts$caption,
color = colors$caption,
lineheight = 1.1,
hjust = 0,
halign = 0,
margin = margin(t = 10, b = 5)
),
)
```
#### [7. Save]{.smallcaps}
```{r}
#| label: save
#| warning: false
### |- plot image ----
save_plot(
p,
type = "30daychartchallenge",
year = 2026,
day = 01,
width = 7,
height = 6
)
```
#### [8. Session Info]{.smallcaps}
::: {.callout-tip collapse="true"}
##### Expand for Session Info
```{r, echo = FALSE}
#| eval: true
#| warning: false
sessionInfo()
```
:::
#### [9. GitHub Repository]{.smallcaps}
::: {.callout-tip collapse="true"}
##### Expand for GitHub Repo
The complete code for this analysis is available in [`30dcc_2026_01.qmd`](https://github.com/poncest/personal-website/blob/master/data_visualizations/TidyTuesday/2026/30dcc_2026_01.qmd).
For the full repository, [click here](https://github.com/poncest/personal-website/).
:::
#### [10. References]{.smallcaps}
::: {.callout-tip collapse="true"}
##### Expand for References
1. Data Sources:
- Congressional Budget Office (CBO). (2025). *Monthly Budget Review: Summary for Fiscal Year 2025*. Retrieved from https://www.cbo.gov/publication/61307
:::
#### [11. Custom Functions Documentation]{.smallcaps}
::: {.callout-note collapse="true"}
##### 📦 Custom Helper Functions
This analysis uses custom functions from my personal module library for efficiency and consistency across projects.
**Functions Used:**
- **`fonts.R`**: `setup_fonts()`, `get_font_families()` - Font management with showtext
- **`social_icons.R`**: `create_social_caption()` - Generates formatted social media captions
- **`image_utils.R`**: `save_plot()` - Consistent plot saving with naming conventions
- **`base_theme.R`**: `create_base_theme()`, `extend_weekly_theme()`, `get_theme_colors()` - Custom ggplot2 themes
**Why custom functions?**\
These utilities standardize theming, fonts, and output across all my data visualizations. The core analysis (data tidying and visualization logic) uses only standard tidyverse packages.
**Source Code:**\
View all custom functions → [GitHub: R/utils](https://github.com/poncest/personal-website/tree/master/R)
:::