This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see http://rmarkdown.rstudio.com.
When you click the Knit button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:
You can also embed plots, for example:
Note that the echo = FALSE parameter was added to the
code chunk to prevent printing of the R code that generated the
plot.
get_row <- function(sheet, row_num, start_col = 3) {
df <- read_excel(xlsx_path, sheet = sheet,
col_names = FALSE, skip = row_num)
as.numeric(df[1, start_col:ncol(df)])
}
# ============================================================
# READ YEAR LABELS (row 4, 0-indexed = skip 4)
# ============================================================
year_row <- read_excel(xlsx_path, sheet = "Table 1.1",
col_names = FALSE, skip = 4)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
year_labels <- as.character(unlist(year_row[1, ]))
year_labels <- year_labels[!is.na(year_labels)]
# Extract numeric start year from labels e.g. "1994-95" -> 1994
years <- as.numeric(substr(year_labels, 1, 4))
cat("Years found:", paste(years, collapse = ", "), "\n")
## Years found: 1994, 1995, 1996, 1997, 1999, 2000, 2002, 2003, 2005, 2007, 2009, 2011, 2013, 2015, 2017, 2019
cat("N years:", length(years), "\n")
## N years: 16
# ============================================================
# TABLE 1.1 DATA (row indices 0-based from inspection)
# Row 8: Owner without mortgage
# Row 9: Owner with mortgage
# Row 13: Total renters
# ============================================================
owner_no_mtg_cost <- get_row("Table 1.1", 8)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
owner_mtg_cost <- get_row("Table 1.1", 9)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
total_renters_cost <- get_row("Table 1.1", 13)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
cat("Owner no mortgage (first 3):", head(owner_no_mtg_cost, 3), "\n")
## Owner no mortgage (first 3): 41 36 36
cat("Owner with mortgage (first 3):", head(owner_mtg_cost, 3), "\n")
## Owner with mortgage (first 3): 351 356 359
cat("Total renters (first 3):", head(total_renters_cost, 3), "\n")
## Total renters (first 3): 218 218 226
# ============================================================
# TABLE 1.2 DATA (housing cost as % of income)
# Row 32: Lowest quintile (Q1)
# Row 33: Second quintile (Q2)
# Row 34: Third quintile (Q3)
# Row 35: Fourth quintile (Q4)
# Row 36: Highest quintile (Q5)
# Row 17: Couple with dependent children
# Row 18: One parent family
# Row 19: Couple only
# Row 23: Lone person
# ============================================================
q1 <- get_row("Table 1.2", 32)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
q2 <- get_row("Table 1.2", 33)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
q3 <- get_row("Table 1.2", 34)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
q4 <- get_row("Table 1.2", 35)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
q5 <- get_row("Table 1.2", 36)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
couple_with_kids <- get_row("Table 1.2", 17)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
single_parent <- get_row("Table 1.2", 18)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
couple_only <- get_row("Table 1.2", 19)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
lone_person <- get_row("Table 1.2", 23)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
cat("Q1 lowest (first 3):", head(q1, 3), "\n")
## Q1 lowest (first 3): 21.9 23.4 22.3
cat("Single parent (first 3):", head(single_parent, 3), "\n")
## Single parent (first 3): 21.4 19.8 20
# ============================================================
# TABLE 1.3 DATA (% of households by tenure)
# Row 9: Owner without mortgage
# Row 10: Owner with mortgage
# Row 14: Private landlord (renters)
# ============================================================
owner_no_mtg_pct <- get_row("Table 1.3", 9)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
owner_mtg_pct <- get_row("Table 1.3", 10)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
private_rent_pct <- get_row("Table 1.3", 14)
## New names:
## • `` -> `...1`
## • `` -> `...2`
## • `` -> `...3`
## • `` -> `...4`
## • `` -> `...5`
## • `` -> `...6`
## • `` -> `...7`
## • `` -> `...8`
## • `` -> `...9`
## • `` -> `...10`
## • `` -> `...11`
## • `` -> `...12`
## • `` -> `...13`
## • `` -> `...14`
## • `` -> `...15`
## • `` -> `...16`
## • `` -> `...17`
## • `` -> `...18`
cat("Owner no mortgage % (first 3):", head(owner_no_mtg_pct, 3), "\n")
## Owner no mortgage % (first 3): 41.8 42.8 41.3
Australia’s housing costs have not risen proportionally. While outright owners pay just $54 per week, renters and mortgage holders have faced steep increases over 25 years reaching $380 and $500 per week respectively by 2019–20. The widening economic difference between owning and not owning is a defining feature of modern Australia. Hover over the lines to view costs per year.
chart1 <- plot_ly(width = 600) %>%
add_trace(
x = years, y = owner_no_mtg_cost,
type = "scatter", mode = "lines+markers",
name = "Owner (no mortgage)",
line = list(color = col_orange, width = 2.5),
marker = list(color = col_orange, size = 6, symbol = "circle"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Owner (no mortgage): $%{y}/week<extra></extra>"
) %>%
add_trace(
x = years, y = owner_mtg_cost,
type = "scatter", mode = "lines+markers",
name = "Owner (with mortgage)",
line = list(color = col_blue, width = 2.5),
marker = list(color = col_blue, size = 6, symbol = "circle"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Owner (with mortgage): $%{y}/week<extra></extra>"
) %>%
add_trace(
x = years, y = total_renters_cost,
type = "scatter", mode = "lines+markers",
name = "Renter",
line = list(color = col_skyblue, width = 2.5),
marker = list(color = col_skyblue, size = 6, symbol = "circle"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Renter: $%{y}/week<extra></extra>"
) %>%
layout(
title = list(
text = "<b>The Widening Gap: Weekly housing costs by tenure, 1994-2020</b><br><sup>Mean weekly housing costs in 2019-20 dollars — renters and mortgage holders face rising costs while outright owners pay little</sup>",
font = list(size = 13, color = col_text), x = 0.01
),
xaxis = list(title = "", tickvals = c(1994,1999,2003,2007,2011,2015,2019),
tickformat = "d", gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
yaxis = list(title = "Mean weekly cost (AUD)", tickprefix = "$",
range = c(0, 560), gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
legend = list(orientation = "h", x = 0, y = -0.15, font = list(size = 10)),
hovermode = "x unified", plot_bgcolor = col_bg, paper_bgcolor = col_bg,
margin = list(l = 65, r = 20, t = 90, b = 80)
) %>%
config(displayModeBar = FALSE)
chart1
Not everyone in Australia is experiencing the housing crisis in the same way. The lowest-income households now spend about 30% of their income on housing, which is far higher than the 30% housing stress threshold, while the wealthiest spend only 9-10%.This disparity has grown over the last 25 years, locking low-income Australians in a loop where escalating expenses leave little for food, healthcare, or savings. Hover to compare quintiles over time.
chart2 <- plot_ly(width = 600) %>%
add_trace(
x = years, y = owner_no_mtg_pct,
type = "scatter", mode = "none",
fill = "tozeroy", fillcolor = col_orange,
name = "Owner (no mortgage)", text = year_labels,
hovertemplate = "<b>%{text}</b><br>Owner (no mortgage): %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = owner_no_mtg_pct + owner_mtg_pct,
type = "scatter", mode = "none",
fill = "tonexty", fillcolor = col_blue,
name = "Owner (with mortgage)", text = year_labels,
hovertemplate = "<b>%{text}</b><br>Owner (with mortgage): %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = owner_no_mtg_pct + owner_mtg_pct + private_rent_pct,
type = "scatter", mode = "none",
fill = "tonexty", fillcolor = col_skyblue,
name = "Private renter", text = year_labels,
hovertemplate = "<b>%{text}</b><br>Private renter: %{y:.1f}%<extra></extra>"
) %>%
layout(
title = list(
text = "<b>Renting is the New Normal: Tenure shifts, 1994-2020</b><br><sup>Proportion of Australian households by tenure type — outright ownership is declining while private renting grows</sup>",
font = list(size = 13, color = col_text), x = 0.01
),
xaxis = list(title = "", tickvals = c(1994,1999,2003,2007,2011,2015,2019),
tickformat = "d", gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
yaxis = list(title = "% of households", ticksuffix = "%",
range = c(0, 100), gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
legend = list(orientation = "h", x = 0, y = -0.15, font = list(size = 10)),
hovermode = "x unified", plot_bgcolor = col_bg, paper_bgcolor = col_bg,
margin = list(l = 65, r = 20, t = 90, b = 80)
) %>%
config(displayModeBar = FALSE)
chart2
Not everyone in Australia is experiencing the housing crisis in the same way. The lowest-income households now spend about 30% of their income on housing, which is far higher than the 30% housing stress threshold, while the wealthiest spend only 9-10%. This disparity has grown over the last 25 years, locking low-income Australians in a loop where escalating expenses leave little for food, healthcare, or savings. Hover to compare quintiles over time.
chart3 <- plot_ly(width = 600) %>%
add_trace(
x = years, y = q1, type = "scatter", mode = "lines+markers",
name = "Lowest income (Q1)",
line = list(color = col_skyblue, width = 2.5),
marker = list(color = col_skyblue, size = 6, symbol = "circle"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Lowest income (Q1): %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = q2, type = "scatter", mode = "lines+markers",
name = "Second (Q2)",
line = list(color = col_blue, width = 2),
marker = list(color = col_blue, size = 5, symbol = "circle"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Second (Q2): %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = q3, type = "scatter", mode = "lines+markers",
name = "Middle (Q3)",
line = list(color = col_orange, width = 2),
marker = list(color = col_orange, size = 5, symbol = "square"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Middle (Q3): %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = q4, type = "scatter", mode = "lines+markers",
name = "Fourth (Q4)",
line = list(color = col_pink, width = 2),
marker = list(color = col_pink, size = 5, symbol = "diamond"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Fourth (Q4): %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = q5, type = "scatter", mode = "lines+markers",
name = "Highest income (Q5)",
line = list(color = col_black, width = 2),
marker = list(color = col_black, size = 5, symbol = "triangle-up"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Highest income (Q5): %{y:.1f}%<extra></extra>"
) %>%
layout(
title = list(
text = "<b>The Rent Trap: Housing cost burden by income group, 1994-2020</b><br><sup>Housing costs as % of gross household income — lowest income households spend 3x more than the wealthiest</sup>",
font = list(size = 13, color = col_text), x = 0.01
),
xaxis = list(title = "", tickvals = c(1994,1999,2003,2007,2011,2015,2019),
tickformat = "d", gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
yaxis = list(title = "Housing cost (% of income)", ticksuffix = "%",
range = c(0, 35), gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
legend = list(orientation = "h", x = 0, y = -0.18, font = list(size = 10)),
hovermode = "x unified", plot_bgcolor = col_bg, paper_bgcolor = col_bg,
margin = list(l = 65, r = 20, t = 90, b = 90)
) %>%
config(displayModeBar = FALSE)
chart3
The housing crisis disproportionately affects those least equipped to cope. Single parents continuously spend more than 20% of their income on housing, rising to 23% by 2017-18, whilst couple-only households spend only 12%.Single-parent families and lone-person households have faced a structural disadvantage for the past 25 years, with substantial consequences for child well-being and social mobility.Hover to compare different family kinds.
chart4 <- plot_ly(width = 600) %>%
add_trace(
x = years, y = single_parent, type = "scatter", mode = "lines+markers",
name = "Single parent",
line = list(color = col_skyblue, width = 2.5),
marker = list(color = col_skyblue, size = 6, symbol = "circle"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Single parent: %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = lone_person, type = "scatter", mode = "lines+markers",
name = "Lone person",
line = list(color = col_orange, width = 2),
marker = list(color = col_orange, size = 5, symbol = "square"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Lone person: %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = couple_with_kids, type = "scatter", mode = "lines+markers",
name = "Couple with children",
line = list(color = col_blue, width = 2),
marker = list(color = col_blue, size = 5, symbol = "diamond"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Couple with children: %{y:.1f}%<extra></extra>"
) %>%
add_trace(
x = years, y = couple_only, type = "scatter", mode = "lines+markers",
name = "Couple only",
line = list(color = col_pink, width = 2),
marker = list(color = col_pink, size = 5, symbol = "triangle-up"),
text = year_labels,
hovertemplate = "<b>%{text}</b><br>Couple only: %{y:.1f}%<extra></extra>"
) %>%
layout(
title = list(
text = "<b>Who Bears the Burden? Housing costs by family type, 1994-2020</b><br><sup>Housing costs as % of gross household income — single parents and lone persons carry the heaviest load</sup>",
font = list(size = 13, color = col_text), x = 0.01
),
xaxis = list(title = "", tickvals = c(1994,1999,2003,2007,2011,2015,2019),
tickformat = "d", gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
yaxis = list(title = "Housing cost (% of income)", ticksuffix = "%",
range = c(0, 28), gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
legend = list(orientation = "h", x = 0, y = -0.15, font = list(size = 10)),
hovermode = "x unified", plot_bgcolor = col_bg, paper_bgcolor = col_bg,
margin = list(l = 65, r = 20, t = 90, b = 80)
) %>%
config(displayModeBar = FALSE)
chart4
Perhaps the most profound consequence of the housing crisis is its impact on life decisions. As homeownership reduced, Australia’s overall fertility rate fell from 1.75 births per woman in 1999 to 1.66 in 2019. At the same time, the median age of moms giving birth has increased from 29.8 to 31.6 years. The Lucky Country is changing not only what people can afford to acquire, but also when and whether they choose to start a family. Hover over each line to see exact values.
tenure_df <- read_csv(
"~/Desktop/housing.csv",
skip = 2,
col_names = c("period","owner_outright","owner_mortgage",
"renter_govt","renter_private"),
show_col_types = FALSE
) %>%
filter(!is.na(owner_outright), grepl("\u2013", period)) %>%
mutate(
year = as.numeric(substr(period, 1, 4)),
owner_outright = as.numeric(owner_outright),
owner_mortgage = as.numeric(owner_mortgage),
homeownership_rate = owner_outright + owner_mortgage
) %>%
select(year, period, homeownership_rate)
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
## dat <- vroom(...)
## problems(dat)
tfr_df <- read_csv(
"~/Desktop/fertility.csv",
skip = 2, col_names = c("year","tfr"),
show_col_types = FALSE
) %>%
filter(!is.na(year), !is.na(tfr), !grepl("[A-Za-z]", year)) %>%
mutate(year = as.numeric(year), tfr = as.numeric(tfr)) %>%
filter(year >= 1999, year <= 2020)
age_df <- read_csv(
"~/Desktop/median_age.csv",
skip = 2,
col_names = c("year","median_age_mother","median_age_father"),
show_col_types = FALSE
) %>%
filter(!is.na(year), !is.na(median_age_mother),
!grepl("[A-Za-z]", year)) %>%
mutate(year = as.numeric(year),
median_age_mother = as.numeric(median_age_mother)) %>%
filter(year >= 1999, year <= 2020)
## Warning: One or more parsing issues, call `problems()` on your data frame for details,
## e.g.:
## dat <- vroom(...)
## problems(dat)
tfr_scale <- 15; tfr_offset <- 38
age_scale <- 2; age_offset <- 2
chart5 <- plot_ly(width = 600) %>%
add_trace(
data = tenure_df, x = ~year, y = ~homeownership_rate,
type = "scatter", mode = "lines+markers",
name = "Homeownership rate (%)",
line = list(color = col_skyblue, width = 3),
marker = list(color = col_skyblue, size = 8, symbol = "circle"),
hovertemplate = "<b>%{x}</b><br>Homeownership: %{y:.1f}%<extra></extra>"
) %>%
add_trace(
data = tfr_df, x = ~year, y = ~(tfr * tfr_scale + tfr_offset),
type = "scatter", mode = "lines+markers",
name = "Total fertility rate",
line = list(color = col_blue, width = 2, dash = "dash"),
marker = list(color = col_blue, size = 5, symbol = "triangle-up"),
text = ~round(tfr, 2),
hovertemplate = "<b>%{x}</b><br>Fertility rate: %{text} births/woman<extra></extra>"
) %>%
add_trace(
data = age_df, x = ~year,
y = ~(median_age_mother * age_scale + age_offset),
type = "scatter", mode = "lines+markers",
name = "Median age of mother",
line = list(color = col_orange, width = 2, dash = "dot"),
marker = list(color = col_orange, size = 5, symbol = "square"),
text = ~round(median_age_mother, 1),
hovertemplate = "<b>%{x}</b><br>Median age of mother: %{text} years<extra></extra>"
) %>%
layout(
title = list(
text = "<b>Delayed Lives: As Australians are priced out, births slow and parenthood is postponed</b><br><sup>Homeownership rate, total fertility rate, and median age of mother — Australia 1999-2020. Fertility rate and age of mother are scaled; hover for exact values.</sup>",
font = list(size = 13, color = col_text), x = 0.01
),
xaxis = list(title = "", tickvals = seq(1999, 2020, by = 3),
tickformat = "d", gridcolor = col_grid,
showline = TRUE, linecolor = "#CCCCCC"),
yaxis = list(title = "Homeownership rate (%)",
titlefont = list(color = col_skyblue, size = 10),
ticksuffix = "%", range = c(55, 80),
gridcolor = col_grid, showline = TRUE, linecolor = "#CCCCCC"),
legend = list(orientation = "h", x = 0, y = -0.15, font = list(size = 10)),
hovermode = "x unified", plot_bgcolor = col_bg, paper_bgcolor = col_bg,
margin = list(l = 65, r = 20, t = 100, b = 80)
) %>%
config(displayModeBar = FALSE)
chart5
Australian Bureau of Statistics. (2022). Housing occupancy and costs, Australia, 2019–20. ABS. https://www.abs.gov.au/statistics/people/housing/housing-occupancy-and-costs/latest-release
Australian Bureau of Statistics. (2024). Births, Australia. ABS. https://www.abs.gov.au/statistics/people/population/births-australia/latest-release
Australian Institute of Health and Welfare. (2021). Home ownership and housing tenure. AIHW. https://www.aihw.gov.au/reports/australias-welfare/home-ownership-and-housing-tenure