Most media coverage of Victoria’s rental crisis focuses on rising median prices in inner Melbourne. But median numbers hide the core issue: how many homes are actually affordable to people on low incomes or Centrelink?
Homes Victoria considers a property affordable if rent takes up 30% or less of gross household income. Using official bond data from the DFFH Rental Report (September Quarter 2025), this report maps where affordable rentals have disappeared over the last two decades across five stages:
We start by comparing annual percentage growth in the Metropolitan Rent Index (MRI) versus the Regional Rent Index (RRI) between 2000 and 2025. These indices adjust for property types and bedroom counts, giving a cleaner look at underlying price changes than simple median rents.
# creating readable tooltip strings for the hover state
df_p1 <- df_plot1_inflation %>%
mutate(
hover_info = paste0(
"<b>Date:</b> ", format(date, "%b %Y"), "<br>",
"<b>Region:</b> ", region, "<br>",
"<b>Annual Change:</b> ", round(annual_pct_change, 2), "%"
)
)
# building the time-series plot comparing both rent indices
p1 <- ggplot(df_p1, aes(x = date, y = annual_pct_change, color = region, group = region, text = hover_info)) +
geom_hline(yintercept = 0, linetype = "dashed", color = "#999999", linewidth = 0.5) +
geom_line(linewidth = 0.85) +
geom_point(size = 1.2, alpha = 0.6) +
scale_color_manual(values = c("Metropolitan Melbourne" = "#1b9e77", "Regional Victoria" = "#d95f02")) +
scale_y_continuous(labels = function(x) paste0(x, "%")) +
scale_x_date(date_breaks = "3 years", date_labels = "%Y") +
labs(
title = "Annual Rent Index Growth in Victoria (2000–2025)",
subtitle = "Metropolitan vs Regional Rent Index annual percentage change",
x = "Year",
y = "Annual Percentage Change (%)",
color = "Region",
caption = "Source: DFFH Rental Report (Sept 2025), Figure 1 source"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 13),
panel.grid.minor = element_blank(),
axis.title.x = element_text(margin = margin(t = 8))
)
# converting to plotly and expand bottom margin so the legend does not hit the x-axis
ggplotly(p1, tooltip = "text") %>%
layout(
margin = list(b = 85, t = 60),
legend = list(
orientation = "h",
x = 0.5,
xanchor = "center",
y = -0.25
)
)
Between 2000 and 2019, regional rent growth consistently stayed below city rates. During the 2020–2022 lockdowns, regional rents surged to nearly 14% annual growth as people relocated from Melbourne. Metro rents eventually caught up in 2023–2024, leaving both markets on a permanently higher price baseline.
Rent inflation hits hardest when incomes lag behind. The chart below tracks the percentage of newly lodged rental bonds that met the DFFH 30% affordability benchmark across Victoria, Melbourne, and the regions from late 2020 to September 2025.
# building tooltip text with formatted percentage numbers
df_p2 <- df_plot2_afford_trend %>%
mutate(
hover_info = paste0(
"<b>Quarter:</b> ", format(date, "%b %Y"), "<br>",
"<b>Area:</b> ", region, "<br>",
"<b>Affordable Share:</b> ", round(pct_affordable, 1), "%"
)
)
# plotting the longitudinal collapse across metro and regional victoria
p2 <- ggplot(df_p2, aes(x = date, y = pct_affordable, color = region, group = region, text = hover_info)) +
geom_line(linewidth = 0.95) +
geom_point(size = 1.7) +
scale_color_manual(values = c(
"Victoria Statewide" = "#7570b3",
"Metropolitan Melbourne" = "#1b9e77",
"Regional Victoria" = "#d95f02"
)) +
scale_y_continuous(labels = function(x) paste0(x, "%"), limits = c(0, 50)) +
scale_x_date(date_breaks = "1 year", date_labels = "%b %Y") +
labs(
title = "Share of New Rentals Affordable to Low-Income Households",
subtitle = "Quarterly proportion of newly lodged bonds within the 30% income threshold",
x = "Quarter",
y = "Affordable Lettings (% of Total)",
color = "Jurisdiction",
caption = "Source: DFFH Rental Report (Sept 2025), Figure 8 source"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 13),
panel.grid.minor = element_blank(),
axis.title.x = element_text(margin = margin(t = 8))
)
# converting to plotly with enough bottom padding for the centered legend
ggplotly(p2, tooltip = "text") %>%
layout(
margin = list(b = 90, t = 60),
legend = list(
orientation = "h",
x = 0.5,
xanchor = "center",
y = -0.28
)
)
In late 2020, over 40% of newly leased regional homes were affordable to low-income earners, compared to roughly 8% in Greater Melbourne. Over the last five years, regional affordability dropped to around 36%, while metro Melbourne has stayed trapped below 10%. Across the entire state, affordable entry-level rentals are disappearing.
Statewide averages mask significant differences between suburbs. Here, every Victorian Local Government Area (LGA) is plotted by quarterly turnover (x-axis, log scale), affordability rate in September 2025 (y-axis), and council group (color). Bubble size represents the total number of affordable homes leased.
# formatting tooltip strings with council metrics and volume
df_p3 <- df_plot3_lga_snapshot %>%
mutate(
hover_info = paste0(
"<b>Council:</b> ", lga, "<br>",
"<b>Region Cohort:</b> ", cohort, "<br>",
"<b>Affordability Rate:</b> ", round(aff_pct_2025, 1), "%<br>",
"<b>Affordable Homes Leased:</b> ", scales::comma(aff_count_2025), "<br>",
"<b>Estimated Total Lettings:</b> ~", scales::comma(total_lettings_2025)
)
)
# drawing multivariate bubble plot on a log10 volume scale
p3 <- ggplot(df_p3, aes(
x = total_lettings_2025,
y = aff_pct_2025,
color = cohort,
size = aff_count_2025,
text = hover_info
)) +
geom_point(alpha = 0.75) +
scale_x_log10(labels = scales::comma) +
scale_y_continuous(labels = function(x) paste0(x, "%")) +
scale_size_continuous(range = c(2.5, 9), guide = "none") +
scale_color_brewer(palette = "Dark2") +
labs(
title = "Council Affordability vs Market Turnover (September 2025)",
subtitle = "Quarterly volume (log scale) reveals exclusion across high-turnover metropolitan LGAs",
x = "Quarterly Lettings Volume (Log Scale)",
y = "Affordable Lettings (%)",
color = "Council Cohort",
caption = "Source: DFFH Rental Report (Sept 2025), Table: lga aff total"
) +
theme_minimal(base_size = 11) +
theme(
legend.position = "right",
plot.title = element_text(face = "bold", size = 13),
panel.grid.minor = element_blank(),
axis.title.x = element_text(margin = margin(t = 8))
)
# converting to plotly and adding right margin so the cohort legend has room
ggplotly(p3, tooltip = "text") %>%
layout(
margin = list(t = 60, b = 60, r = 40)
)
Inner and middle metro councils handle the bulk of bond turnover but sit almost flat along the bottom axis with affordability rates between 0% and 2%. Outer growth corridors like Wyndham and Casey have also seen affordability compress into single digits. The only areas where affordability remains above 40% are smaller rural shires with very low turnover and few local job options.
When Melbourne rents became too expensive, regional centers like Geelong, Ballarat, and Bendigo served as affordable alternatives. This dumbbell plot compares the share of affordable lettings in September 2020 (blue dot) versus September 2025 (red dot) across key regional cities and outer fringes.
# ordering councils by their 2020 baseline and format period tooltips
df_p4 <- df_plot4_regional_shift %>%
mutate(
lga_ordered = factor(lga, levels = rev(lga)),
hover_2020 = paste0("<b>Council:</b> ", lga, "<br><b>Period:</b> Sep 2020<br><b>Affordability:</b> ", round(aff_pct_2020, 1), "%"),
hover_2025 = paste0("<b>Council:</b> ", lga, "<br><b>Period:</b> Sep 2025<br><b>Affordability:</b> ", round(aff_pct_2025, 1), "%<br><b>5-Yr Drop:</b> ", round(pct_point_drop, 1), " pp")
)
# drawing dumbbell segments connecting 2020 and 2025 data points
p4 <- ggplot(df_p4, aes(y = lga_ordered)) +
geom_segment(
aes(x = aff_pct_2020, xend = aff_pct_2025, y = lga_ordered, yend = lga_ordered),
color = "#cfd8dc",
linewidth = 1.4
) +
geom_point(aes(x = aff_pct_2020, color = "Sep 2020", text = hover_2020), size = 3.5) +
geom_point(aes(x = aff_pct_2025, color = "Sep 2025", text = hover_2025), size = 3.5) +
scale_color_manual(
name = "",
values = c("Sep 2020" = "#2b83ba", "Sep 2025" = "#d7191c")
) +
scale_x_continuous(labels = function(x) paste0(x, "%"), limits = c(0, 85)) +
labs(
title = "Regional Affordability Shift: 2020 vs 2025",
x = "Affordable Lettings (% of Total)",
y = "",
caption = "Source: DFFH Rental Report (Sept 2025)"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 13),
panel.grid.major.y = element_blank(),
axis.title.x = element_text(margin = margin(t = 10))
)
# converting to plotly, widening left margin for council names, placing legend cleanly on top
ggplotly(p4, tooltip = "text") %>%
layout(
margin = list(l = 150, r = 40, t = 60, b = 60),
legend = list(
orientation = "h",
x = 0.65,
y = 1.08,
xanchor = "left"
)
)
Regional hubs experienced the steepest drops in low-income housing access. In Latrobe, affordable lettings fell by 20 percentage points (from ~77% to 57%), while Ballarat and Greater Shepparton dropped by more than 15 percentage points. The regional buffer that once protected lower-income renters has eroded considerably.
To measure real-world access, Homes Victoria models four representative household archetypes receiving Centrelink support. This chart shows what percentage of newly leased properties in September 2025 fell within their 30% affordability limit.
# formatting tooltip strings with rent limits, income, and unit counts
df_p5 <- df_plot5_cohorts %>%
mutate(
hover_info = paste0(
"<b>Household Type:</b> ", cohort, "<br>",
"<b>Region:</b> ", region, "<br>",
"<b>Target Dwelling:</b> ", dwelling, "<br>",
"<b>Weekly Income:</b> $", scales::comma(income), "<br>",
"<b>Max Affordable Rent:</b> $", scales::comma(max_rent), "/wk<br>",
"<b>Share of New Lettings:</b> ", pct, "%<br>",
"<b>Actual Number of Units:</b> ", scales::comma(units)
)
)
# creating grouped bar chart comparing metro vs regional access
p5 <- ggplot(df_p5, aes(x = cohort, y = pct, fill = region, text = hover_info)) +
geom_col(position = position_dodge(width = 0.8), width = 0.7) +
scale_fill_manual(values = c("Metropolitan Melbourne" = "#1b9e77", "Regional Victoria" = "#d95f02")) +
scale_y_continuous(labels = function(x) paste0(x, "%"), limits = c(0, 50)) +
labs(
title = "Rental Market Access by Household Archetype (September 2025)",
subtitle = "Percentage of newly lodged bonds affordable within the 30% income threshold",
x = "Household Archetype",
y = "Accessible Lettings (% of Total)",
fill = "",
caption = "Source: DFFH Rental Report (Sept 2025), Table 9"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold", size = 13),
axis.text.x = element_text(angle = 12, hjust = 1),
axis.title.x = element_text(margin = margin(t = 10))
)
# converting to plotly, placing legend on top right so angled x-labels have ample room
ggplotly(p5, tooltip = "text") %>%
layout(
margin = list(b = 90, t = 60),
legend = list(
orientation = "h",
x = 0.55,
y = 1.08,
xanchor = "left"
)
)
Single-earner and single-parent households face near-total exclusion. For a single person on JobSeeker ($225/week rent limit), only 1% of 1-bedroom apartments (77 units total) in metropolitan Melbourne were affordable that quarter. Viable options only emerge for dual-earner households, like a couple on the minimum wage, who can access 26% of metro homes and 45% of regional homes.
The September 2025 bond data points to three main conclusions:
In accordance with RMIT University academic integrity guidelines, Generative AI tools were used exclusively for technical programming support and coding syntax, specifically troubleshooting R Markdown YAML configurations, resolving Plotly canvas margin overlaps, and formatting APA 7th edition references.
All analytical observations, data cleaning scripts and wrangling pipelines, chart designs, and written descriptions represent my own work.