library(ggplot2)
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
housing_data <- data.frame(
year = c(2000,
2001,
2002,
2003,
2004,
2005,
2006,
2007,
2008,
2009,
2010,
2011,
2012,
2013,
2014,
2015,
2016,
2017,
2018,
2019,
2020,
2021,
2022,
2023,
2024,
2025),
years_salary = c(
4.32,
5.63,
5.58,
6.47,
6.33,
6.30,
6.62,
6.75,
6.75,
7.56,
7.72,
7.15,
7.21,
7.72,
8.10,
8.66,
9.18,
9.46,
8.81,
8.87,
9.11,
10.89,
9.79,
10.09,
10.42,
10.84
)
)
#Add annotations
housing_data <- housing_data %>%
mutate(
annotation = case_when(
year == 2008 ~ "Global Financial Crisis",
year == 2017 ~ "Peak before 2018 dip",
year == 2021 ~ "Post-COVID surge",
year == 2025 ~ "Projected",
TRUE ~ NA_character_
),
hover_text = paste0(
"<b>", year, "</b><br>",
"Years of salary needed: ", round(years_salary, 2), "<br>",
ifelse(!is.na(annotation), paste0(annotation, "<br>"), ""),
"Drag to zoom and Double click to reset"
)
)
#Create the plot
p1_base <- ggplot(housing_data, aes(x = year, y = years_salary, text = hover_text)) +
geom_line(color = "#004B87", size = 1.2) +
geom_point(color = "#004B87", size = 2.5, alpha = 0.7) +
#Reference line
geom_hline(yintercept = 4.32, linetype = "dashed", color = "#E57200", alpha = 0.6, size = 0.8) +
labs(
x = "Year",
y = "Years of full-time salary needed to buy a median home"
) +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", size = 16, color = "#1a1a1a"),
plot.subtitle = element_text(size = 11, color = "#666666", margin = margin(b = 15)),
axis.title = element_text(size = 11, face = "bold"),
axis.text = element_text(size = 10),
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank()
) +
scale_y_continuous(
limits = c(0, 13),
breaks = seq(0, 13, by = 2),
labels = function(x) paste0(x, " years")
) +
scale_x_continuous(
breaks = seq(2000, 2025, by = 5),
limits = c(1998, 2026)
) +
annotate(
"text",
x = 2025, y = 10.84,
label = "2025: 10.8 years",
color = "#E57200",
size = 3.2,
fontface = "bold",
hjust = 0
) +
annotate(
"text",
x = 2000, y = 4.32,
label = "2000 baseline\n(4.3 years)",
color = "#E57200",
size = 3,
hjust = 0
)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
p1_interactive <- ggplotly(p1_base, tooltip = "text") %>%
layout(
title = list(
text = "<b>Years of full-time salary needed to buy a median-priced home</b>",
font = list(size = 14),
x = 0,
xanchor = "left"
),
xaxis = list(
title = "Year",
rangeselector = list(
buttons = list(
list(count = 5, label = "5 Yr", step = "year", stepmode = "backward"),
list(count = 10, label = "10 Yr", step = "year", stepmode = "backward"),
list(step = "all")
)
),
rangeslider = list(type = "x")
),
yaxis = list(
title = "Years of full-time salary needed",
zeroline = FALSE
),
hoverlabel = list(
bgcolor = "white",
font = list(size = 11),
bordercolor = "#004B87"
),
annotations = list(
list(
x = 0,
y = -0.15,
xref = "paper",
yref = "paper",
text = "Data: ABS/HPI (2010=100), CoreLogic. Income estimates from ABS wage data. 2025 projected.",
showarrow = FALSE,
font = list(size = 9, color = "#999999")
)
)
) %>%
style(
line = list(color = "#004B87", width = 2),
marker = list(color = "#004B87", size = 6),
hoverinfo = "text"
)
p1_interactive
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...
## A line object has been specified, but lines is not in the mode
## Adding lines to the mode...
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...
## A line object has been specified, but lines is not in the mode
## Adding lines to the mode...
## A marker object has been specified, but markers is not in the mode
## Adding markers to the mode...
## A line object has been specified, but lines is not in the mode
## Adding lines to the mode...