• Steven Ponce
  • About
  • Data Visualizations
  • Projects
  • Resume
  • Email

On this page

  • Original
  • Makeover
  • Steps to Create this Graphic
    • 1. Load Packages & Setup
    • 2. Read in the Data
    • 3. Examine the Data
    • 4. Tidy Data
    • 5. Visualization Parameters
    • 6. Plot
    • 7. Save
    • 8. Session Info
    • 9. GitHub Repository
    • 10. References

UK Household Spending Inequality by Income Level in FYE 2024

  • Show All Code
  • Hide All Code

  • View Source

Housing costs create the largest spending gap between rich and poor households

MakeoverMonday
Data Visualization
R Programming
2025
UK household spending analysis reveals housing costs burden poor families disproportionately, creating the largest spending gap across income groups. Visualization explores spending inequality across all categories using ONS Family Spending Survey data.
Published

September 24, 2025

Original

The original visualization Figure 5: Poorer households spent proportionally more on housing, fuel and power than richer households in FYE 2024 - Average weekly household expenditure as a percentage of total weekly expenditure, by quintile group, UK, financial year ending (FYE) 2024 comes from Family spending in the UK: April 2023 to March 2024

Original visualization

Makeover

Figure 1: Two-panel chart showing UK household spending inequality by income in 2024. The left panel displays spending gaps between the poorest and wealthiest households across 11 categories, with housing showing the largest gap at 13.9 percentage points. The right panel shows distribution patterns across all five income quintiles using ridge plots. Housing costs disproportionately burden poor households, while transport spending favors wealthy households.

Steps to Create this Graphic

1. Load Packages & Setup

Show code
```{r}
#| label: load
#| warning: false
#| message: false
#| results: "hide"

## 1. LOAD PACKAGES & SETUP ----
suppressPackageStartupMessages({
  if (!require("pacman")) install.packages("pacman")
  pacman::p_load(
  tidyverse,  # Easily Install and Load the 'Tidyverse'
  ggtext,     # Improved Text Rendering Support for 'ggplot2'
  showtext,   # Using Fonts More Easily in R Graphs
  scales,     # Scale Functions for Visualization
  glue,       # Interpreted String Literals
  patchwork,  # Using Fonts More Easily in R Graphs
  ggridges    # Ridgeline Plots in 'ggplot2'
  )
})

### |- figure size ----
camcorder::gg_record(
    dir    = here::here("temp_plots"),
    device = "png",
    width  = 12,
    height = 10,
    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

Show code
```{r}
#| label: read
#| include: true
#| eval: true
#| warning: false
#|
households_spending_raw <- read_csv(
  here::here('data/MakeoverMonday/2025/Figure_5__Poorer_households_spent_proportionally_more_on_housing,_fuel_and_power_than_richer_households_in_FYE_2024.csv')) |> 
  janitor::clean_names()
```

3. Examine the Data

Show code
```{r}
#| label: examine
#| include: true
#| eval: true
#| results: 'hide'
#| warning: false

glimpse(households_spending_raw)
skimr::skim_without_charts(households_spending_raw)
```

4. Tidy Data

Show code
```{r}
#| label: tidy
#| warning: false

# Create lookup tables
quintile_labels <- c(
  "bottom_fifth" = "Bottom fifth",
  "x2nd" = "2nd quintile",
  "x3rd" = "3rd quintile",
  "x4th" = "4th quintile",
  "top_fifth" = "Top fifth",
  "all_households" = "All households"
)

# Use the category names from the data
category_lookup <- c(
  "Food and non-alcoholic drinks" = "Food & non-alcoholic drinks",
  "Alcoholic drink tobacco and narcotics" = "Alcohol, tobacco & narcotics", # Note: no comma in original
  "Clothing and footwear" = "Clothing & footwear",
  "Housing (net) fuel and power" = "Housing, fuel & power", # Note: no comma in original
  "Household goods and services" = "Household goods & services",
  "Transport" = "Transport",
  "Communication" = "Communication",
  "Recreation and culture" = "Recreation & culture",
  "Restaurants and hotels" = "Restaurants & hotels",
  "Miscellaneous goods and services" = "Miscellaneous goods & services",
  "Other expenditure items" = "Other expenditure"
)

# Data prep
households_spending_clean <- households_spending_raw |>
  pivot_longer(
    cols = -percent_of_total_weekly_expendtiure,
    names_to = "income_quintile",
    values_to = "percentage"
  ) |>
  rename(category = percent_of_total_weekly_expendtiure) |>
  mutate(
    # Clean quintile names
    income_quintile = quintile_labels[income_quintile],
    income_quintile = factor(income_quintile, levels = quintile_labels),

    # Clean category names using direct lookup
    category_clean = category_lookup[category]
  ) |>
  filter(income_quintile != "All households") |>
  group_by(category_clean) |>
  mutate(gap = max(percentage) - min(percentage)) |>
  ungroup() |>
  mutate(category_clean = fct_reorder(category_clean, gap, .desc = FALSE))

# Dot plot data
dot_data <- households_spending_clean |>
  group_by(category_clean) |>
  summarise(
    poorest_pct = percentage[income_quintile == "Bottom fifth"],
    richest_pct = percentage[income_quintile == "Top fifth"],
    gap = first(gap),
    .groups = "drop"
  )

# Ridges plot data
ridges_data <- households_spending_clean
```

5. Visualization Parameters

Show code
```{r}
#| label: params
#| include: true
#| warning: false

### |-  plot aesthetics ----
# Get base colors with custom palette
colors <- get_theme_colors(palette = list(
  primary = "#2C3E50",      
  secondary = "#E67E22",    
  accent = "#95A5A6",       
  light_gray = "#BDC3C7",   
  dark_gray = "#7F8C8D"     
))   

### |-  titles and caption ----
title_text <- str_glue("UK Household Spending Inequality by Income Level in FYE 2024")

subtitle_text <-str_glue(
  "Housing costs create the largest spending gap between rich and poor households"
)

# Create caption
caption_text <- create_mm_caption(
  mm_year = current_year,
  mm_week = current_week,
  source_text = paste0("UK Office for National Statistics")
)

### |-  fonts ----
setup_fonts()
fonts <- get_font_families()

### |-  plot theme ----

# Start with base theme
base_theme <- create_base_theme(colors)

# Add weekly-specific theme elements
weekly_theme <- extend_weekly_theme(
  base_theme,
  theme(
    # Text styling
    plot.title = element_text(
      size = rel(1.4), family = fonts$title, face = "bold",
      color = colors$title, lineheight = 1.1, hjust = 0,
      margin = margin(t = 5, b = 10)
    ),
    plot.subtitle = element_text(
      size = rel(0.9), family = fonts$subtitle, face = "italic",
      color = alpha(colors$subtitle, 0.9), lineheight = 1.1,
      margin = margin(t = 0, b = 20)
    ),

    # Legend formatting
    legend.position = "plot",
    legend.justification = "top",
    legend.margin = margin(l = 12, b = 5),
    legend.key.size = unit(0.8, "cm"),
    legend.box.margin = margin(b = 10),
    legend.title = element_text(face = "bold"),

    # Axis formatting
    axis.ticks.y = element_blank(),
    axis.ticks.x = element_line(color = "gray", linewidth = 0.5),
    # axis.ticks.length = unit(0.2, "cm"),
    axis.title.x = element_text(
      face = "bold", size = rel(0.85),
      margin = margin(t = 10)
    ),
    axis.title.y = element_text(
      face = "bold", size = rel(0.85),
      margin = margin(r = 10)
    ),
    axis.text.x = element_text(
      size = rel(0.85), family = fonts$subtitle,
      color = colors$text
    ),
    axis.text.y = element_text(
      size = rel(0.85), family = fonts$subtitle,
      color = colors$text
    ),

    # Grid lines
    panel.grid.minor = element_line(color = "#ecf0f1", linewidth = 0.2),
    panel.grid.major = element_line(color = "#ecf0f1", linewidth = 0.4),

    # Margin
    plot.margin = margin(20, 20, 20, 20)
  )
)

# Set theme
theme_set(weekly_theme)
```

6. Plot

Show code
```{r}
#| label: plot
#| warning: false

### |- P1: Range Dot Plot ----
p1 <- dot_data |>
  ggplot(aes(y = category_clean)) +
  # Geoms
  geom_segment(aes(x = richest_pct, xend = poorest_pct, yend = category_clean),
               linewidth = 1, color = colors$palette$light_gray, alpha = 0.6
  ) +
  geom_point(aes(x = richest_pct), size = 4, color = colors$palette$primary) +  
  geom_point(aes(x = poorest_pct), size = 4, color = colors$palette$secondary) +   
  geom_text(
    aes(
      x = (richest_pct + poorest_pct) / 2,
      label = glue("{round(gap,1)} pp")
    ),
    vjust = -1.8, size = 3.3,
    color = colors$palette$primary
  ) +

  # Annotate
  annotate("point", x = 22, y = 1.5, size = 4, color = colors$palette$primary) + # Richest
  annotate("text",
    x = 23, y = 1.5, label = "Richest households",
    color = colors$palette$primary, size = 3.2, fontface = "bold", hjust = 0
  ) +
  annotate("point", x = 22, y = 1, size = 4, color = colors$palette$secondary) + # Poorest
  annotate("text",
    x = 23, y = 1, label = "Poorest households",
    color = colors$palette$secondary, size = 3.2, fontface = "bold", hjust = 0
  ) +

  # Scales
  scale_x_continuous(
    labels = percent_format(scale = 1),
    expand = expansion(mult = c(0.02, 0.1)),
    limits = c(0, 40)
  ) +

  # Labs
  labs(
    title = "Spending Inequality Across Categories",
    subtitle = str_wrap("Range between poorest and richest households (percentage points gap shown)",
      width = 65
    ),
    x = "Percentage of total weekly expenditure",
    y = NULL,
  ) +

  # Theme
  theme(
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(color = "#F0F0F0", linewidth = 0.5),
    panel.grid.minor = element_blank()
  )

### |- P2: Ridgeline Plot ----
p2 <- ridges_data |>
  ggplot(aes(x = percentage, y = category_clean)) +
  # Geoms
  geom_density_ridges(
    alpha = 0.8,
    scale = 1.2,
    rel_min_height = 0.01,
    color = "white",
    linewidth = 0.8,
    fill = colors$palette$accent
  ) +

  # Scales
  scale_x_continuous(
    labels = percent_format(scale = 1),
    expand = expansion(mult = c(0.02, 0.05))
  ) +

  # Labs
  labs(
    title = "Distribution Across Quintiles",
    subtitle = str_wrap("Spending patterns within each category",
      width = 40
    ),
    x = "Percentage of total weekly expenditure",
    y = NULL,
  ) +

  # Theme
  theme(
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(color = "#F0F0F0", linewidth = 0.5),
    panel.grid.minor = element_blank()
  )

### |- Combined Plots ----
combined_plots <- p1 + p2 +
  plot_layout(ncol = 2, widths = c(1.4, 1.1))

combined_plots +
  plot_annotation(
    title = title_text,
    subtitle = subtitle_text,
    caption = caption_text,
    theme = theme(
      plot.title = element_text(
        size = rel(1.6),
        family = fonts$title,
        face = "bold",
        color = colors$title,
        lineheight = 1.1,
        margin = margin(t = 5, b = 5)
      ),
      plot.subtitle = element_markdown(
        size = rel(0.95),
        family = fonts$subtitle,
        color = alpha(colors$subtitle, 0.9),
        lineheight = 1.2,
        margin = margin(t = 5, b = 10)
      ),
      plot.caption = element_markdown(
        size = rel(0.6),
        family = fonts$caption,
        color = colors$caption,
        hjust = 0.5,
        margin = margin(t = 05)
      )
    )
  )
```

7. Save

Show code
```{r}
#| label: save
#| warning: false

### |-  plot image ----  
save_plot_patchwork(
  plot = combined_plots, 
  type = "makeovermonday", 
  year = current_year,
  week = current_week,
  width = 12, 
  height = 10
  )
```

8. Session Info

TipExpand for Session Info
R version 4.4.1 (2024-06-14 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 22631)

Matrix products: default


locale:
[1] LC_COLLATE=English_United States.utf8 
[2] LC_CTYPE=English_United States.utf8   
[3] LC_MONETARY=English_United States.utf8
[4] LC_NUMERIC=C                          
[5] LC_TIME=English_United States.utf8    

time zone: America/New_York
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices datasets  utils     methods   base     

other attached packages:
 [1] here_1.0.1      ggridges_0.5.6  patchwork_1.3.0 glue_1.8.0     
 [5] scales_1.3.0    showtext_0.9-7  showtextdb_3.0  sysfonts_0.8.9 
 [9] ggtext_0.1.2    lubridate_1.9.3 forcats_1.0.0   stringr_1.5.1  
[13] dplyr_1.1.4     purrr_1.0.2     readr_2.1.5     tidyr_1.3.1    
[17] tibble_3.2.1    ggplot2_3.5.1   tidyverse_2.0.0 pacman_0.5.1   

loaded via a namespace (and not attached):
 [1] gtable_0.3.6       xfun_0.49          htmlwidgets_1.6.4  tzdb_0.5.0        
 [5] yulab.utils_0.1.8  vctrs_0.6.5        tools_4.4.0        generics_0.1.3    
 [9] curl_6.0.0         parallel_4.4.0     gifski_1.32.0-1    fansi_1.0.6       
[13] pkgconfig_2.0.3    ggplotify_0.1.2    skimr_2.1.5        lifecycle_1.0.4   
[17] compiler_4.4.0     farver_2.1.2       munsell_0.5.1      repr_1.1.7        
[21] janitor_2.2.0      codetools_0.2-20   snakecase_0.11.1   htmltools_0.5.8.1 
[25] yaml_2.3.10        crayon_1.5.3       pillar_1.9.0       camcorder_0.1.0   
[29] magick_2.8.5       commonmark_1.9.2   tidyselect_1.2.1   digest_0.6.37     
[33] stringi_1.8.4      labeling_0.4.3     rsvg_2.6.1         rprojroot_2.0.4   
[37] fastmap_1.2.0      grid_4.4.0         colorspace_2.1-1   cli_3.6.4         
[41] magrittr_2.0.3     base64enc_0.1-3    utf8_1.2.4         withr_3.0.2       
[45] bit64_4.5.2        timechange_0.3.0   rmarkdown_2.29     bit_4.5.0         
[49] hms_1.1.3          evaluate_1.0.1     knitr_1.49         markdown_1.13     
[53] gridGraphics_0.5-1 rlang_1.1.6        gridtext_0.1.5     Rcpp_1.0.13-1     
[57] xml2_1.3.6         renv_1.0.3         vroom_1.6.5        svglite_2.1.3     
[61] rstudioapi_0.17.1  jsonlite_1.8.9     R6_2.5.1           fs_1.6.5          
[65] systemfonts_1.1.0 

9. GitHub Repository

TipExpand for GitHub Repo

The complete code for this analysis is available in mm_2025_39.qmd.

For the full repository, click here.

10. References

TipExpand for References
  1. Data:
  • Makeover Monday 2025 Week 39: Family spending in the UK
  1. Article
  • Family spending in the UK
Back to top
Source Code
---
title: "UK Household Spending Inequality by Income Level in FYE 2024"
subtitle: "Housing costs create the largest spending gap between rich and poor households"
description: "UK household spending analysis reveals housing costs burden poor families disproportionately, creating the largest spending gap across income groups. Visualization explores spending inequality across all categories using ONS Family Spending Survey data."
date: "2025-09-24" 
categories: ["MakeoverMonday", "Data Visualization", "R Programming", "2025"]   
tags: [
  "household-spending",
  "income-inequality", 
  "housing-costs",
  "uk-statistics",
  "ons-data",
  "data-storytelling",
  "ggplot2",
  "ridge-plots",
  "dot-plots",
  "social-policy"
]
image: "thumbnails/mm_2025_39.png"
format:
  html:
    toc: true
    toc-depth: 5
    code-link: true
    code-fold: true
    code-tools: true
    code-summary: "Show code"
    self-contained: true
    theme: 
      light: [flatly, assets/styling/custom_styles.scss]
      dark: [darkly, assets/styling/custom_styles_dark.scss]
editor_options: 
  chunk_output_type: inline
execute: 
  freeze: true                                      
  cache: true                                       
  error: false
  message: false
  warning: false
  eval: true
---

```{r}
#| label: setup-links
#| include: false

# CENTRALIZED LINK MANAGEMENT

## Project-specific info 
current_year <- 2025
current_week <- 39
project_file <- "mm_2025_39.qmd"
project_image <- "mm_2025_39.png"

## Data Sources
data_main <- "https://data.world/makeovermonday/2025w39-family-spending-in-the-uk"
data_secondary <- "https://data.world/makeovermonday/2025w39-family-spending-in-the-uk"

## Repository Links  
repo_main <- "https://github.com/poncest/personal-website/"
repo_file <- paste0("https://github.com/poncest/personal-website/blob/master/data_visualizations/MakeoverMonday/", current_year, "/", project_file)

## External Resources/Images
chart_original <- "https://raw.githubusercontent.com/poncest/MakeoverMonday/refs/heads/master/2025/Week_39/original_chart.png"

## Organization/Platform Links
org_primary <- "https://www.ons.gov.uk/peoplepopulationandcommunity/personalandhouseholdfinances/expenditure/bulletins/familyspendingintheuk/april2023tomarch2024#data-sources-and-quality"
org_secondary <- "https://www.ons.gov.uk/"

# Helper function to create markdown links
create_link <- function(text, url) {
  paste0("[", text, "](", url, ")")
}

# Helper function for citation-style links
create_citation_link <- function(text, url, title = NULL) {
  if (is.null(title)) {
    paste0("[", text, "](", url, ")")
  } else {
    paste0("[", text, "](", url, ' "', title, '")')
  }
}
```

### Original

The original visualization **Figure 5: Poorer households spent proportionally more on housing, fuel and power than richer households in FYE 2024 - Average weekly household expenditure as a percentage of total weekly expenditure, by quintile group, UK, financial year ending (FYE) 2024** comes from `r create_link("Family spending in the UK: April 2023 to March 2024", data_secondary)`

<!-- ![Original visualization](`r chart_original`) -->

![Original visualization](https://raw.githubusercontent.com/poncest/MakeoverMonday/refs/heads/master/2025/Week_39/original_chart.png)

### Makeover

![Two-panel chart showing UK household spending inequality by income in 2024. The left panel displays spending gaps between the poorest and wealthiest households across 11 categories, with housing showing the largest gap at 13.9 percentage points. The right panel shows distribution patterns across all five income quintiles using ridge plots. Housing costs disproportionately burden poor households, while transport spending favors wealthy households.](mm_2025_39.png){#fig-1}

### <mark> **Steps to Create this Graphic** </mark>

#### 1. Load Packages & Setup

```{r}
#| label: load
#| warning: false
#| message: false      
#| results: "hide"     

## 1. LOAD PACKAGES & SETUP ----
suppressPackageStartupMessages({
  if (!require("pacman")) install.packages("pacman")
  pacman::p_load(
  tidyverse,  # Easily Install and Load the 'Tidyverse'
  ggtext,     # Improved Text Rendering Support for 'ggplot2'
  showtext,   # Using Fonts More Easily in R Graphs
  scales,     # Scale Functions for Visualization
  glue,       # Interpreted String Literals
  patchwork,  # Using Fonts More Easily in R Graphs
  ggridges    # Ridgeline Plots in 'ggplot2'
  )
})

### |- figure size ----
camcorder::gg_record(
    dir    = here::here("temp_plots"),
    device = "png",
    width  = 12,
    height = 10,
    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

```{r}
#| label: read
#| include: true
#| eval: true
#| warning: false
#| 
households_spending_raw <- read_csv(
  here::here('data/MakeoverMonday/2025/Figure_5__Poorer_households_spent_proportionally_more_on_housing,_fuel_and_power_than_richer_households_in_FYE_2024.csv')) |> 
  janitor::clean_names()
```

#### 3. Examine the Data

```{r}
#| label: examine
#| include: true
#| eval: true
#| results: 'hide'
#| warning: false

glimpse(households_spending_raw)
skimr::skim_without_charts(households_spending_raw)
```

#### 4. Tidy Data

```{r}
#| label: tidy
#| warning: false

# Create lookup tables
quintile_labels <- c(
  "bottom_fifth" = "Bottom fifth",
  "x2nd" = "2nd quintile",
  "x3rd" = "3rd quintile",
  "x4th" = "4th quintile",
  "top_fifth" = "Top fifth",
  "all_households" = "All households"
)

# Use the category names from the data
category_lookup <- c(
  "Food and non-alcoholic drinks" = "Food & non-alcoholic drinks",
  "Alcoholic drink tobacco and narcotics" = "Alcohol, tobacco & narcotics", # Note: no comma in original
  "Clothing and footwear" = "Clothing & footwear",
  "Housing (net) fuel and power" = "Housing, fuel & power", # Note: no comma in original
  "Household goods and services" = "Household goods & services",
  "Transport" = "Transport",
  "Communication" = "Communication",
  "Recreation and culture" = "Recreation & culture",
  "Restaurants and hotels" = "Restaurants & hotels",
  "Miscellaneous goods and services" = "Miscellaneous goods & services",
  "Other expenditure items" = "Other expenditure"
)

# Data prep
households_spending_clean <- households_spending_raw |>
  pivot_longer(
    cols = -percent_of_total_weekly_expendtiure,
    names_to = "income_quintile",
    values_to = "percentage"
  ) |>
  rename(category = percent_of_total_weekly_expendtiure) |>
  mutate(
    # Clean quintile names
    income_quintile = quintile_labels[income_quintile],
    income_quintile = factor(income_quintile, levels = quintile_labels),

    # Clean category names using direct lookup
    category_clean = category_lookup[category]
  ) |>
  filter(income_quintile != "All households") |>
  group_by(category_clean) |>
  mutate(gap = max(percentage) - min(percentage)) |>
  ungroup() |>
  mutate(category_clean = fct_reorder(category_clean, gap, .desc = FALSE))

# Dot plot data
dot_data <- households_spending_clean |>
  group_by(category_clean) |>
  summarise(
    poorest_pct = percentage[income_quintile == "Bottom fifth"],
    richest_pct = percentage[income_quintile == "Top fifth"],
    gap = first(gap),
    .groups = "drop"
  )

# Ridges plot data
ridges_data <- households_spending_clean
```

#### 5. Visualization Parameters

```{r}
#| label: params
#| include: true
#| warning: false

### |-  plot aesthetics ----
# Get base colors with custom palette
colors <- get_theme_colors(palette = list(
  primary = "#2C3E50",      
  secondary = "#E67E22",    
  accent = "#95A5A6",       
  light_gray = "#BDC3C7",   
  dark_gray = "#7F8C8D"     
))   

### |-  titles and caption ----
title_text <- str_glue("UK Household Spending Inequality by Income Level in FYE 2024")

subtitle_text <-str_glue(
  "Housing costs create the largest spending gap between rich and poor households"
)

# Create caption
caption_text <- create_mm_caption(
  mm_year = current_year,
  mm_week = current_week,
  source_text = paste0("UK Office for National Statistics")
)

### |-  fonts ----
setup_fonts()
fonts <- get_font_families()

### |-  plot theme ----

# Start with base theme
base_theme <- create_base_theme(colors)

# Add weekly-specific theme elements
weekly_theme <- extend_weekly_theme(
  base_theme,
  theme(
    # Text styling
    plot.title = element_text(
      size = rel(1.4), family = fonts$title, face = "bold",
      color = colors$title, lineheight = 1.1, hjust = 0,
      margin = margin(t = 5, b = 10)
    ),
    plot.subtitle = element_text(
      size = rel(0.9), family = fonts$subtitle, face = "italic",
      color = alpha(colors$subtitle, 0.9), lineheight = 1.1,
      margin = margin(t = 0, b = 20)
    ),

    # Legend formatting
    legend.position = "plot",
    legend.justification = "top",
    legend.margin = margin(l = 12, b = 5),
    legend.key.size = unit(0.8, "cm"),
    legend.box.margin = margin(b = 10),
    legend.title = element_text(face = "bold"),

    # Axis formatting
    axis.ticks.y = element_blank(),
    axis.ticks.x = element_line(color = "gray", linewidth = 0.5),
    # axis.ticks.length = unit(0.2, "cm"),
    axis.title.x = element_text(
      face = "bold", size = rel(0.85),
      margin = margin(t = 10)
    ),
    axis.title.y = element_text(
      face = "bold", size = rel(0.85),
      margin = margin(r = 10)
    ),
    axis.text.x = element_text(
      size = rel(0.85), family = fonts$subtitle,
      color = colors$text
    ),
    axis.text.y = element_text(
      size = rel(0.85), family = fonts$subtitle,
      color = colors$text
    ),

    # Grid lines
    panel.grid.minor = element_line(color = "#ecf0f1", linewidth = 0.2),
    panel.grid.major = element_line(color = "#ecf0f1", linewidth = 0.4),

    # Margin
    plot.margin = margin(20, 20, 20, 20)
  )
)

# Set theme
theme_set(weekly_theme)
```

#### 6. Plot

```{r}
#| label: plot
#| warning: false

### |- P1: Range Dot Plot ----
p1 <- dot_data |>
  ggplot(aes(y = category_clean)) +
  # Geoms
  geom_segment(aes(x = richest_pct, xend = poorest_pct, yend = category_clean),
               linewidth = 1, color = colors$palette$light_gray, alpha = 0.6
  ) +
  geom_point(aes(x = richest_pct), size = 4, color = colors$palette$primary) +  
  geom_point(aes(x = poorest_pct), size = 4, color = colors$palette$secondary) +   
  geom_text(
    aes(
      x = (richest_pct + poorest_pct) / 2,
      label = glue("{round(gap,1)} pp")
    ),
    vjust = -1.8, size = 3.3,
    color = colors$palette$primary
  ) +

  # Annotate
  annotate("point", x = 22, y = 1.5, size = 4, color = colors$palette$primary) + # Richest
  annotate("text",
    x = 23, y = 1.5, label = "Richest households",
    color = colors$palette$primary, size = 3.2, fontface = "bold", hjust = 0
  ) +
  annotate("point", x = 22, y = 1, size = 4, color = colors$palette$secondary) + # Poorest
  annotate("text",
    x = 23, y = 1, label = "Poorest households",
    color = colors$palette$secondary, size = 3.2, fontface = "bold", hjust = 0
  ) +

  # Scales
  scale_x_continuous(
    labels = percent_format(scale = 1),
    expand = expansion(mult = c(0.02, 0.1)),
    limits = c(0, 40)
  ) +

  # Labs
  labs(
    title = "Spending Inequality Across Categories",
    subtitle = str_wrap("Range between poorest and richest households (percentage points gap shown)",
      width = 65
    ),
    x = "Percentage of total weekly expenditure",
    y = NULL,
  ) +

  # Theme
  theme(
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(color = "#F0F0F0", linewidth = 0.5),
    panel.grid.minor = element_blank()
  )

### |- P2: Ridgeline Plot ----
p2 <- ridges_data |>
  ggplot(aes(x = percentage, y = category_clean)) +
  # Geoms
  geom_density_ridges(
    alpha = 0.8,
    scale = 1.2,
    rel_min_height = 0.01,
    color = "white",
    linewidth = 0.8,
    fill = colors$palette$accent
  ) +

  # Scales
  scale_x_continuous(
    labels = percent_format(scale = 1),
    expand = expansion(mult = c(0.02, 0.05))
  ) +

  # Labs
  labs(
    title = "Distribution Across Quintiles",
    subtitle = str_wrap("Spending patterns within each category",
      width = 40
    ),
    x = "Percentage of total weekly expenditure",
    y = NULL,
  ) +

  # Theme
  theme(
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    panel.grid.major.x = element_blank(),
    panel.grid.major.y = element_line(color = "#F0F0F0", linewidth = 0.5),
    panel.grid.minor = element_blank()
  )

### |- Combined Plots ----
combined_plots <- p1 + p2 +
  plot_layout(ncol = 2, widths = c(1.4, 1.1))

combined_plots <- combined_plots +
  plot_annotation(
    title = title_text,
    subtitle = subtitle_text,
    caption = caption_text,
    theme = theme(
      plot.title = element_text(
        size = rel(1.6),
        family = fonts$title,
        face = "bold",
        color = colors$title,
        lineheight = 1.1,
        margin = margin(t = 5, b = 5)
      ),
      plot.subtitle = element_markdown(
        size = rel(0.95),
        family = fonts$subtitle,
        color = alpha(colors$subtitle, 0.9),
        lineheight = 1.2,
        margin = margin(t = 5, b = 10)
      ),
      plot.caption = element_markdown(
        size = rel(0.6),
        family = fonts$caption,
        color = colors$caption,
        hjust = 0.5,
        margin = margin(t = 05)
      )
    )
  )
```

#### 7. Save

```{r}
#| label: save
#| warning: false

### |-  plot image ----  
save_plot_patchwork(
  plot = combined_plots, 
  type = "makeovermonday", 
  year = current_year,
  week = current_week,
  width = 12, 
  height = 10
  )
```

#### 8. Session Info

::: {.callout-tip collapse="true"}
##### Expand for Session Info

```{r, echo = FALSE}
#| eval: true
#| warning: false

sessionInfo()
```
:::

#### 9. GitHub Repository

::: {.callout-tip collapse="true"}
##### Expand for GitHub Repo

The complete code for this analysis is available in `r create_link(project_file, repo_file)`.

For the full repository, `r create_link("click here", repo_main)`.
:::

#### 10. References

::: {.callout-tip collapse="true"}
##### Expand for References

1.  Data:

-   Makeover Monday `r current_year` Week `r current_week`: `r create_link("Family spending in the UK", data_main)`

2.  Article

-   `r create_link("Family spending in the UK", data_secondary)`
:::

© 2024 Steven Ponce

Source Issues