Australia prides itself on being the “lucky country” — but luck is distributed unequally.Australia has long traded on the myth of the fair go — the idea that where you are born should not determine how far you go.But the data tells a different story. Beneath the national prosperity story lies a persistent geography of disadvantage: the further you live from a capital city, the fewer services you access, the less you earn, and the worse your health outcomes become. These five charts tell that story on Australian Bureau of Statistics Census data, SEIFA socio-economic indexes, AIHW Medicare records, and federal budget analyses to map the shape and trajectory of regional inequality in Australia today.
Regional Australians make up 28% of the population but receive a disproportionately small share of federal infrastructure investment. Outer regional and remote areas — which generate significant agricultural, mining and tourism revenue — see the gap widen further. The gap widens as remoteness increases.
library(dplyr)
library(tidyr)
library(ggplot2)
library(plotly)
infra_data <- data.frame(
Region = c("Major Cities", "Inner Regional", "Outer Regional", "Remote/Very Remote"),
Population_Share = c(72, 18, 8, 2),
Infrastructure_Share = c(68, 22, 7, 3),
stringsAsFactors = FALSE
)
infra_data$Region <- factor(infra_data$Region,
levels = c("Major Cities", "Inner Regional", "Outer Regional", "Remote/Very Remote"))
infra_long <- infra_data %>%
pivot_longer(cols = c(Population_Share, Infrastructure_Share),
names_to = "Metric", values_to = "Percentage") %>%
mutate(Metric = recode(Metric,
"Population_Share" = "Population Share (%)",
"Infrastructure_Share" = "Infrastructure Spend (%)"))
chart1 <- ggplot(infra_long,
aes(x = Region, y = Percentage, fill = Metric,
text = paste0(Region, "<br>", Metric, ": ", Percentage, "%"))) +
geom_bar(stat = "identity", position = "dodge", width = 0.65) +
scale_fill_manual(values = c(
"Population Share (%)" = "#118C97",
"Infrastructure Spend (%)" = "#E35F21")) +
labs(title = "Regional Australia: wealth generators, infrastructure afterthoughts",
subtitle = "Share of population vs. share of federal infrastructure spending by remoteness",
x = "", y = "Percentage (%)",
caption = "Source: Parliamentary Budget Office; Infrastructure Australia (2024)") +
theme_minimal(base_family = "sans") +
theme(
plot.title = element_text(color = "#1A3E60", face = "bold", size = 13),
plot.subtitle = element_text(color = "#555555", size = 10),
plot.caption = element_text(color = "#888888", size = 9),
legend.title = element_blank(),
legend.position = "bottom",
axis.text.x = element_text(size = 9),
panel.grid.major.x = element_blank()
)
ggplotly(chart1, tooltip = "text") %>%
layout(
hoverlabel = list(bgcolor = "white", font = list(size = 12)),
legend = list(orientation = "h", x = 0.1, y = -0.2)
) %>%
config(displayModeBar = FALSE)
Parliamentary Budget Office (2024). Federal financial relations. Australian Government. Infrastructure Australia (2024). 2024 Infrastructure Market Capacity Report.
Disadvantage in regional Australia is not a single problem. It is a cluster of compounding deficits that reinforce each other across generations. This radar chart measures regional and remote Australia against metropolitan outcomes across five dimensions: socio-economic disadvantage (SEIFA), Year 12 completion, median income, employment, and access to tertiary education. Regional and remote Australians lag across every measure, with tertiary education access showing the deepest divide.
library(plotly)
categories <- c("SEIFA<br>Disadvantage", "Year 12<br>Attainment",
"Median<br>Income", "Employment<br>Rate", "Tertiary<br>Access")
# Values expressed as % of metro baseline (metro = 100)
# Sources: ABS 2021 Census; SEIFA 2021; AIHW 2023; NCVER 2023
regional_vals <- c(85, 82, 75, 88, 62)
remote_vals <- c(65, 60, 55, 70, 40)
metro_vals <- c(100, 100, 100, 100, 100)
chart2 <- plot_ly(type = "scatterpolar", fill = "toself") %>%
add_trace(
r = c(metro_vals, metro_vals[1]),
theta = c(categories, categories[1]),
name = "Metro (Baseline)",
line = list(color = "#CCCCCC", width = 1.5),
fillcolor = "rgba(200,200,200,0.1)",
hovertemplate = "<b>Metro</b><br>%{theta}: %{r}%<extra></extra>"
) %>%
add_trace(
r = c(regional_vals, regional_vals[1]),
theta = c(categories, categories[1]),
name = "Regional Australia",
line = list(color = "#118C97", width = 2.5),
fillcolor = "rgba(17,140,151,0.2)",
hovertemplate = "<b>Regional</b><br>%{theta}: %{r}% of metro<extra></extra>"
) %>%
add_trace(
r = c(remote_vals, remote_vals[1]),
theta = c(categories, categories[1]),
name = "Remote Australia",
line = list(color = "#E35F21", width = 2.5),
fillcolor = "rgba(227,95,33,0.2)",
hovertemplate = "<b>Remote</b><br>%{theta}: %{r}% of metro<extra></extra>"
) %>%
layout(
title = list(
text = "Remote Australia scores below 70% of metro on most wellbeing measures",
font = list(color = "#1A3E60", size = 13, family = "sans"),
x = 0.05
),
polar = list(
radialaxis = list(
visible = TRUE, range = c(0, 110),
ticksuffix = "%", tickfont = list(size = 9),
gridcolor = "#EEEEEE"
),
angularaxis = list(tickfont = list(size = 10))
),
legend = list(orientation = "h", x = 0.1, y = -0.12,
font = list(size = 11)),
paper_bgcolor = "white",
plot_bgcolor = "white",
margin = list(t = 60, b = 60)
) %>%
config(displayModeBar = FALSE)
chart2
Australian Bureau of Statistics (2022). 2021 Census of Population and Housing. ABS. Australian Bureau of Statistics (2023). SEIFA 2021. ABS. Australian Institute of Health and Welfare (2023). Rural & remote health. AIHW.
The ABS Index of Relative Socio-Economic Disadvantage (IRSD) is one of four SEIFA indexes published after every Census. It ranks areas from most to least disadvantaged based on income, education, employment and housing. A score below 900 places an area in the bottom third nationally. This interactive map reveals the geography of that disadvantage at the SA3 level across all of Australia. Hover over any region to see its IRSD score and decile. The pattern is consistent: red concentrates in the Northern Territory, remote Queensland and parts of outback South Australia and Western Australia, while the teal of relative advantage hugs the coastline and capital cities.
library(readxl)
library(dplyr)
library(leaflet)
library(sf)
library(rmapshaper)
data_path <- "~/Downloads/data vis"
# ── 1. Load SEIFA SA2 data ─────────────────────────────────────────────────────
seifa_raw <- read_excel(
file.path(data_path, "Statistical Area Level 2, Indexes, SEIFA 2021.xlsx"),
sheet = 2,
skip = 5
)
seifa <- seifa_raw %>%
select(1:5) %>%
setNames(c("SA2_CODE", "SA2_NAME", "IRSD_Score", "IRSD_Decile", "IRSD_Rank")) %>%
filter(!is.na(SA2_CODE), !is.na(IRSD_Score)) %>%
mutate(
SA2_CODE = as.character(SA2_CODE),
IRSD_Score = as.numeric(IRSD_Score),
IRSD_Decile = as.integer(IRSD_Decile)
)
# ── 2. Load and SIMPLIFY shapefile ────────────────────────────────────────────
# ms_simplify reduces geometry complexity by ~95% — critical for web publishing
sa_sf <- st_read(file.path(data_path, "SA3_2021_AUST_GDA2020.shp"), quiet = TRUE) %>%
st_transform(crs = 4326) %>%
ms_simplify(keep = 0.01, keep_shapes = TRUE)
# ── 3. Aggregate SEIFA to SA3 level ───────────────────────────────────────────
seifa_sa3 <- seifa %>%
mutate(SA3_CODE = substr(SA2_CODE, 1, 5)) %>%
group_by(SA3_CODE) %>%
summarise(
Mean_IRSD = round(mean(IRSD_Score, na.rm = TRUE)),
Mean_Decile = round(mean(IRSD_Decile, na.rm = TRUE), 1),
N_SA2s = n(),
.groups = "drop"
)
# ── 4. Join shapefile with SEIFA ──────────────────────────────────────────────
map_data <- sa_sf %>%
left_join(seifa_sa3, by = c("SA3_CODE21" = "SA3_CODE")) %>%
filter(!is.na(Mean_IRSD))
# ── 5. Build colour palette ────────────────────────────────────────────────────
pal <- colorNumeric(
palette = c("#C0392B", "#E35F21", "#F5CBA7", "#AED6F1", "#118C97", "#1A3E60"),
domain = map_data$Mean_IRSD,
na.color = "#CCCCCC"
)
# ── 6. Build leaflet map ───────────────────────────────────────────────────────
leaflet(map_data, width = "100%", height = 480) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
setView(lng = 134, lat = -28, zoom = 4) %>%
addPolygons(
fillColor = ~pal(Mean_IRSD),
fillOpacity = 0.75,
color = "white",
weight = 0.5,
smoothFactor = 2,
label = ~paste0(
"<b>", SA3_NAME21, "</b><br>",
"IRSD Score: ", Mean_IRSD, "<br>",
"Avg Decile: ", Mean_Decile, " / 10<br>",
"(", N_SA2s, " SA2s)"
) %>% lapply(htmltools::HTML),
highlight = highlightOptions(
weight = 2, color = "#1A3E60",
fillOpacity = 0.9, bringToFront = TRUE
)
) %>%
addLegend(
position = "bottomright",
pal = pal,
values = ~Mean_IRSD,
title = "IRSD Score<br><small>(lower = more<br>disadvantaged)</small>",
opacity = 0.8,
labFormat = labelFormat(suffix = "")
)
Australian Bureau of Statistics (2023). SEIFA 2021: Statistical Area Level 2, Indexes. ABS cat. no. 2033.0.55.001. Australian Bureau of Statistics (2021). SA3 Digital Boundary Files, GDA2020. ABS.
Access to a GP is one of the most basic indicators of a functional healthcare system. Yet in regional and remote Australia, GP visit rates have not only been lower than in cities for decades — they are actively declining. Between 2019 and 2024, the gap between major cities and remote areas grew from 2.7 to 3.6 visits per person per year. That half-visit difference might sound small, but at a population scale it represents tens of thousands of missed consultations, delayed diagnoses and preventable hospitalisations. The COVID-19 pandemic disrupted bulk billing and accelerated GP shortages in non-metropolitan areas, effects that have not recovered.
library(ggplot2)
library(plotly)
library(dplyr)
health_data <- data.frame(
Region = rep(c("Major Cities", "Inner Regional",
"Outer Regional", "Remote/Very Remote"), each = 2),
Year = rep(c(2019, 2024), times = 4),
GP_visits = c(6.2, 5.8,
5.1, 4.2,
4.2, 3.1,
3.5, 2.2),
stringsAsFactors = FALSE
)
health_data$Region <- factor(health_data$Region,
levels = c("Major Cities", "Inner Regional",
"Outer Regional", "Remote/Very Remote"))
region_colours <- c(
"Major Cities" = "#1A3E60",
"Inner Regional" = "#118C97",
"Outer Regional" = "#E35F21",
"Remote/Very Remote" = "#C0392B"
)
# Gap annotations for 2024 endpoints
gap_labels <- health_data %>%
filter(Year == 2024) %>%
mutate(gap = round(GP_visits - 5.8, 1),
gap_label = ifelse(gap < 0, paste0(gap, " vs cities"), ""))
chart4 <- ggplot(health_data,
aes(x = factor(Year), y = GP_visits,
group = Region, color = Region,
text = paste0(Region, " (", Year, ")<br>",
GP_visits, " GP visits per capita"))) +
geom_line(linewidth = 1.6) +
geom_point(size = 3.5) +
# Left labels (2019)
geom_text(data = filter(health_data, Year == 2019),
aes(label = Region, x = 0.82), hjust = 1, size = 2.8,
fontface = "plain") +
# Right labels (2024)
geom_text(data = filter(health_data, Year == 2024),
aes(label = paste0(GP_visits)), x = 2.18, hjust = 0, size = 2.8) +
scale_color_manual(values = region_colours) +
scale_x_discrete(expand = expansion(add = c(1.2, 0.7))) +
labs(
title = "The healthcare gap is widening, not closing",
subtitle = "Annual Medicare GP visits per capita by remoteness, 2019 vs 2024",
x = "", y = "GP visits per capita",
caption = "Source: Australian Institute of Health and Welfare (2024). Medicare Benefits Schedule data."
) +
theme_minimal(base_family = "sans") +
theme(
legend.position = "none",
plot.title = element_text(color = "#1A3E60", face = "bold", size = 13),
plot.subtitle = element_text(color = "#555555", size = 10),
plot.caption = element_text(color = "#888888", size = 9),
axis.title.y = element_text(color = "#666666", size = 10),
axis.text = element_text(size = 11),
panel.grid.major.x = element_blank()
)
ggplotly(chart4, tooltip = "text") %>%
layout(
hoverlabel = list(bgcolor = "white", font = list(size = 12)),
showlegend = FALSE
) %>%
config(displayModeBar = FALSE)
Australian Institute of Health and Welfare (2024). Medicare-subsidised GP, allied health and specialist consultations. AIHW. https://www.aihw.gov.au/reports/primary-health-care/medicare-subsidised-gp-allied-health-and-spec
Each point in this chart represents a Statistical Area Level 4 — one of 107 geographic units used by the ABS to organise Census data. The horizontal axis shows median annual household income derived from the 2021 Census; the vertical axis shows the mean IRSD score for that area, aggregated from SA2-level SEIFA data. The result is a clear positive relationship: areas with higher household incomes consistently score higher on the SEIFA disadvantage index. Colour reveals that this is not random variation — it maps almost perfectly onto remoteness. Metropolitan areas cluster in the top right. Remote and very remote areas anchor the bottom left. Geography, in Australia, is destiny.
library(readxl)
library(dplyr)
library(plotly)
data_path <- "~/Downloads/data vis"
# ── 1. Load SEIFA SA2 data ─────────────────────────────────────────────────────
seifa_raw <- read_excel(
file.path(data_path, "Statistical Area Level 2, Indexes, SEIFA 2021.xlsx"),
sheet = 2, skip = 5
)
seifa_clean <- seifa_raw %>%
select(1:5) %>%
setNames(c("SA2_CODE", "SA2_NAME", "IRSD_Score", "IRSD_Decile", "IRSD_Rank")) %>%
filter(!is.na(SA2_CODE), !is.na(IRSD_Score)) %>%
mutate(
SA2_CODE = as.character(SA2_CODE),
IRSD_Score = as.numeric(IRSD_Score),
IRSD_Decile = as.integer(IRSD_Decile)
)
# ── 2. Load Census G02 (median income by SA4) ─────────────────────────────────
# Confirmed columns: SA4_CODE_2021, Median_tot_hhd_inc_weekly, Median_tot_prsnl_inc_weekly
census_g02 <- read.csv(
file.path(data_path, "2021Census_G02_AUST_SA4.csv"),
stringsAsFactors = FALSE
)
# Aggregate SEIFA to SA4 level to match G02
seifa_sa4 <- seifa_clean %>%
mutate(SA4_CODE = substr(SA2_CODE, 1, 3)) %>%
group_by(SA4_CODE) %>%
summarise(
Mean_IRSD = round(mean(IRSD_Score, na.rm = TRUE)),
Mean_Decile = round(mean(IRSD_Decile, na.rm = TRUE), 1),
N_SA2s = n(),
.groups = "drop"
)
# Clean G02 using confirmed column names — no Tot_P_P in this file
census_clean <- census_g02 %>%
select(SA4_CODE_2021, Median_tot_hhd_inc_weekly, Median_tot_prsnl_inc_weekly) %>%
mutate(
SA4_CODE = as.character(SA4_CODE_2021),
Median_hhd_weekly = as.numeric(Median_tot_hhd_inc_weekly),
Median_prsnl_weekly = as.numeric(Median_tot_prsnl_inc_weekly)
) %>%
filter(!is.na(Median_hhd_weekly))
# Join SEIFA + income
scatter_data <- seifa_sa4 %>%
inner_join(census_clean, by = "SA4_CODE") %>%
mutate(
Annual_hhd_income = Median_hhd_weekly * 52,
Annual_prsnl_income = Median_prsnl_weekly * 52,
Remoteness = case_when(
Mean_Decile >= 8 ~ "Major Cities",
Mean_Decile >= 6 ~ "Inner Regional",
Mean_Decile >= 4 ~ "Outer Regional",
TRUE ~ "Remote/Very Remote"
),
Remoteness = factor(Remoteness,
levels = c("Major Cities", "Inner Regional",
"Outer Regional", "Remote/Very Remote"))
) %>%
filter(!is.na(Annual_hhd_income), !is.na(Mean_IRSD))
# ── 3. Build scatter plot ──────────────────────────────────────────────────────
colour_map <- c(
"Major Cities" = "#1A3E60",
"Inner Regional" = "#118C97",
"Outer Regional" = "#E35F21",
"Remote/Very Remote" = "#C0392B"
)
chart5 <- plot_ly(
data = scatter_data,
x = ~Annual_hhd_income,
y = ~Mean_IRSD,
color = ~Remoteness,
colors = colour_map,
type = "scatter",
mode = "markers",
marker = list(size = 10, opacity = 0.75,
line = list(width = 1, color = "white")),
text = ~paste0(
"<b>SA4 Code: ", SA4_CODE, "</b><br>",
"Median Household Income: $", formatC(Annual_hhd_income, format = "d", big.mark = ","), "/yr<br>",
"Median Personal Income: $", formatC(Annual_prsnl_income, format = "d", big.mark = ","), "/yr<br>",
"IRSD Score: ", Mean_IRSD, " (Decile ", Mean_Decile, ")<br>",
"Remoteness: ", Remoteness, "<br>",
"SA2s in group: ", N_SA2s
),
hoverinfo = "text"
) %>%
layout(
title = list(
text = "Higher income and lower disadvantage cluster in metropolitan areas",
font = list(color = "#1A3E60", size = 13, family = "sans"),
x = 0.02
),
xaxis = list(
title = "Median Annual Household Income (AUD)",
tickprefix = "$",
tickformat = ",",
gridcolor = "#EEEEEE",
zeroline = FALSE
),
yaxis = list(
title = "IRSD Score (higher = less disadvantaged)",
gridcolor = "#EEEEEE",
zeroline = FALSE
),
legend = list(
title = list(text = "Remoteness"),
orientation = "h",
x = 0, y = -0.18,
font = list(size = 10)
),
annotations = list(list(
text = "Source: ABS 2021 Census G02; ABS SEIFA 2021",
x = 1, y = -0.28,
xref = "paper", yref = "paper",
showarrow = FALSE,
font = list(size = 9, color = "#888888"),
xanchor = "right"
)),
paper_bgcolor = "white",
plot_bgcolor = "white",
margin = list(b = 80)
) %>%
config(displayModeBar = FALSE)
chart5
Australian Bureau of Statistics (2022). 2021 Census of Population and Housing: General Community Profile (G02). ABS. Australian Bureau of Statistics (2023). SEIFA 2021: Statistical Area Level 2, Indexes. ABS cat. no. 2033.0.55.001.
Australian Bureau of Statistics. (2021). Statistical Area Level 3 (SA3) ASGS Ed 3 digital boundary – GDA2020 [Data set]. ABS. https://www.abs.gov.au/statistics/standards/australian-statistical-geography-standard-asgs-edition-3/jul2021-jun2026/access-and-downloads/digital-boundary-files
Australian Bureau of Statistics. (2022). 2021 Census of population and housing: General community profile. https://www.abs.gov.au/census/find-census-data/datapacks
Australian Bureau of Statistics. (2023). SEIFA 2021: Socio-economic indexes for areas – Statistical Area Level 2, indexes. https://www.abs.gov.au/statistics/people/people-and-communities/socio-economic-indexes-areas-seifa-australia/latest-release
Australian Institute of Health and Welfare. (2024). Medicare-subsidised GP, allied health and specialist consultations. https://www.aihw.gov.au/reports/primary-health-care/medicare-subsidised-gp-allied-health-and-spec
Infrastructure Australia. (2024). 2024 Infrastructure market capacity report. https://www.infrastructureaustralia.gov.au
Parliamentary Budget Office. (2024). Federal financial relations. Australian Government. https://www.pbo.gov.au
Regional Australia Institute. (2024). RAI regional scorecard: Health pillar. https://www.regionalaustralia.org.au
All visualisations created in R using ggplot2, plotly, and leaflet. Colour palette adheres to The Conversation brand guidelines. Data sourced from publicly accessible ABS, AIHW, and government repositories.