# ---- Load data ---------------------------------------------------------------
# Crime Statistics Agency (2026), Victim Reports data tables, year ending June 2026.
# The file is read locally; if it is missing it is downloaded directly from the source.
data_file <- "Data_Tables_Victim_Reports_Visualisation_Year_Ending_June_2026.xlsx"
data_url <- paste0("https://files.crimestatistics.vic.gov.au/2026-09/", data_file)
if (!file.exists(data_file)) download.file(data_url, data_file, mode = "wb")
t02 <- read_excel(data_file, sheet = "Table 02") # victims by sex and age (counts + rates)
t04 <- read_excel(data_file, sheet = "Table 04") # victims by sex, age and offence (counts only)
t02 <- t02 |>
rename(year = Year, sex = Sex, age = `Age Group`,
reports = `Victim Reports`, rate = `Rate per 100,000 population`) |>
filter(sex %in% c("Females", "Males", "People"),
!age %in% c("Total", "Organisations"))
t04 <- t04 |>
rename(year = Year, sex = Sex, age = `Age Group`, division = `Offence Division`,
offence = `Offence Subdivision`, reports = `Victim Reports`) |>
filter(sex %in% c("Females", "Males", "People"),
age != "Total", !grepl("Total", offence))
# ---- Pre-processing ----------------------------------------------------------
# 1. Back-calculate the population behind each Table 02 rate:
# population = reports / rate x 100,000
# 2. Group the 5-year age groups into the wider bands used in Table 04 and sum
# the populations, so the offence-level counts in Table 04 can also be
# expressed as rates per 100,000 (removing the effect of population growth).
age_levels <- c("00-04 years", "05-09 years", "10-14 years", "15-17 years",
"18-19 years", "20-24 years", "25-29 years", "30-34 years",
"35-39 years", "40-44 years", "45-49 years", "50-54 years",
"55-59 years", "60-64 years", "65-69 years", "70-74 years",
"75 years and over")
band_levels <- c("0–17", "18–24", "25–34", "35–44", "45–54", "55–64", "65–74", "75+")
to_band <- function(age) {
case_when(
age %in% c("00-04 years", "05-09 years", "10-14 years", "15-17 years", "00-17 years") ~ "0–17",
age %in% c("18-19 years", "20-24 years", "18-24 years") ~ "18–24",
age %in% c("25-29 years", "30-34 years", "25-34 years") ~ "25–34",
age %in% c("35-39 years", "40-44 years", "35-44 years") ~ "35–44",
age %in% c("45-49 years", "50-54 years", "45-54 years") ~ "45–54",
age %in% c("55-59 years", "60-64 years", "55-64 years") ~ "55–64",
age %in% c("65-69 years", "70-74 years", "65-74 years") ~ "65–74",
age == "75 years and over" ~ "75+"
)
}
# Shorter, plain-English offence labels
tidy_offence <- function(x) {
x <- trimws(gsub("[A-Z][0-9]{2} ", "", x))
recode(x,
"Assault and related offences" = "Assault",
"Stalking, harassment and threatening behaviour" = "Stalking, harassment & threats",
"Arson & Property damage" = "Arson & property damage",
"Burglary/Break and enter" = "Burglary / break and enter",
"Deception" = "Deception (fraud, scams)")
}
t02 <- t02 |>
mutate(pop = reports / rate * 1e5,
age = factor(age, levels = age_levels),
band = factor(to_band(as.character(age)), levels = band_levels))
pop_band <- t02 |>
group_by(year, sex, band) |>
summarise(reports = sum(reports), pop = sum(pop), .groups = "drop") |>
mutate(rate = reports / pop * 1e5)
# Offence-level rates by sex and age band
offence_rates <- t04 |>
mutate(band = factor(to_band(age), levels = band_levels),
offence = tidy_offence(offence)) |>
group_by(year, sex, band, offence) |>
summarise(reports = sum(reports), .groups = "drop") |>
left_join(select(pop_band, year, sex, band, pop), by = c("year", "sex", "band")) |>
mutate(rate = reports / pop * 1e5)
Crime statistics are usually told through the lens of young people: young offenders, young victims, nights out gone wrong. On that front, the news in Victoria’s latest figures is mostly good. Over the decade to June 2026, the chance of being recorded as a victim of crime fell for most age groups under 50 (Crime Statistics Agency, 2026).
But one group moved the other way. Victorians in their fifties, sixties, seventies and beyond became steadily more likely to be victims. The number of Victorians aged 75 and over grew by about 38% over the same period, so this is a growing group facing a growing risk. The five charts below follow that story: where the gap opens, how it built up, what is driving it, the scam surge at its centre, and who it affects most.
How to explore: every chart is interactive. Hover for exact values, use the buttons and menus above each chart to switch views, click legend items to hide or show groups, and drag to zoom (double-click to reset). Open “View underlying data” under any chart to see the exact numbers behind it.
This first chart sets up the whole story by comparing two snapshots taken ten years apart. Each row is a five-year age group. The hollow circle shows how many people in that group were recorded as victims of crime per 100,000 in 2017, the filled circle shows the same rate in 2026, and the line between them is blue where the rate fell and orange where it rose. Reading from top to bottom, a clear split appears. In 10 of the 11 age groups under 50, the rate fell; for people aged 25–29, for example, it dropped by 7%. From 50–54 onwards, every single age group rose, and people aged 70–74 were 18% more likely to be recorded as a victim in 2026 than in 2017. Young adults still have the highest rates overall, so older Victorians are not yet the most victimised group, but they are the only part of the population moving in the wrong direction. Use the buttons above the chart to switch between all people, women and men. The turning point at 50 holds for both sexes, and the rise is steeper for women: among 70–74 year olds, the rate rose 31% for women compared with 13% for men.
c1 <- t02 |>
filter(year %in% c(2017, 2026)) |>
select(sex, age, year, rate) |>
pivot_wider(names_from = year, values_from = rate, names_prefix = "r") |>
mutate(change = r2026 / r2017 - 1,
dir = ifelse(change >= 0, "Rate rose", "Rate fell"),
tip = paste0("<b>", age, "</b><br>2017: ", fmt(r2017), " per 100,000",
"<br>2026: ", fmt(r2026), " per 100,000",
"<br>Change: ", sgn(change), fmt(change * 100), "%"))
sex_views <- c(People = "all people", Females = "women", Males = "men")
first_older <- which(age_levels == "50-54 years") - 1
c1_title <- function(s) list(
text = paste0("<b>Victimisation fell for most under-50s but rose for every age group from 50 up</b>",
"<br><sup>Victim reports per 100,000 people, ", sex_views[[s]],
", Victoria, year ending June 2017 vs 2026</sup>"),
x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top")
p1 <- plot_ly(); grp1 <- character()
for (s in names(sex_views)) {
d <- filter(c1, sex == s)
for (dd in c("Rate fell", "Rate rose")) {
dsub <- filter(d, dir == dd)
if (nrow(dsub) == 0) next
p1 <- add_segments(p1, data = dsub, x = ~r2017, xend = ~r2026, y = ~age, yend = ~age,
name = dd, legendgroup = dd, visible = (s == "People"),
line = list(color = ifelse(dd == "Rate rose", col_rise, col_fall), width = 4),
text = ~tip, hoverinfo = "text")
grp1 <- c(grp1, s)
}
p1 <- add_markers(p1, data = d, x = ~r2017, y = ~age, name = "2017", legendgroup = "2017",
visible = (s == "People"), text = ~tip, hoverinfo = "text",
marker = list(color = "white", size = 9, line = list(color = "#555555", width = 2)))
p1 <- add_markers(p1, data = d, x = ~r2026, y = ~age, name = "2026", legendgroup = "2026",
visible = (s == "People"), text = ~tip, hoverinfo = "text",
marker = list(color = "#222222", size = 9))
grp1 <- c(grp1, s, s)
}
buttons1 <- lapply(names(sex_views), function(s) {
list(method = "update", label = c(People = "All people", Females = "Women", Males = "Men")[[s]],
args = list(list(visible = grp1 == s), list(title = c1_title(s))))
})
p1 |>
layout(
title = c1_title("People"), font = font_main,
xaxis = list(title = "Victim reports per 100,000 people", zeroline = FALSE, tickformat = ","),
yaxis = list(title = "", categoryorder = "array", categoryarray = age_levels),
shapes = list(list(type = "rect", xref = "paper", x0 = 0, x1 = 1,
y0 = first_older - 0.5, y1 = length(age_levels) - 0.5,
fillcolor = col_rise, opacity = 0.07, line = list(width = 0))),
annotations = list(
list(xref = "paper", x = 0.99, y = length(age_levels) - 1.3, xanchor = "right",
text = "<b>Aged 50+:</b> every group up", showarrow = FALSE,
font = list(color = col_rise, size = 13)),
src_note("Crime Statistics Agency (2026), Victim Reports, Table 02.")),
updatemenus = list(list(type = "buttons", direction = "right", buttons = buttons1,
x = 0, xanchor = "left", y = 1.02, yanchor = "bottom",
bgcolor = "#F4F4F4", bordercolor = "#BBBBBB")),
legend = list(orientation = "h", x = 1, xanchor = "right", y = 1.02, yanchor = "bottom"),
margin = list(t = 150, b = 110)
) |>
tidy_config()
Chart description: a dumbbell chart of 17 age groups, with buttons to switch between all people, women and men. Each row joins the 2017 rate (hollow circle) to the 2026 rate (filled circle). In every view, the rows from 50–54 upwards are orange, meaning the rate rose; most rows for children and adults under 50 are blue, meaning the rate fell.
| Group | Age group | Rate 2017 | Rate 2026 | Change |
|---|---|---|---|---|
| All people | 00-04 years | 238 | 142 | -40% |
| All people | 05-09 years | 446 | 281 | -37% |
| All people | 10-14 years | 1,267 | 1,175 | -7% |
| All people | 15-17 years | 2,568 | 2,655 | +3% |
| All people | 18-19 years | 4,120 | 3,923 | -5% |
| All people | 20-24 years | 5,538 | 5,018 | -9% |
| All people | 25-29 years | 5,960 | 5,535 | -7% |
| All people | 30-34 years | 5,781 | 5,572 | -4% |
| All people | 35-39 years | 5,516 | 5,340 | -3% |
| All people | 40-44 years | 5,419 | 5,068 | -6% |
| All people | 45-49 years | 5,037 | 4,885 | -3% |
| All people | 50-54 years | 4,421 | 4,799 | +9% |
| All people | 55-59 years | 3,664 | 4,126 | +13% |
| All people | 60-64 years | 2,976 | 3,472 | +17% |
| All people | 65-69 years | 2,422 | 2,808 | +16% |
| All people | 70-74 years | 1,879 | 2,222 | +18% |
| All people | 75 years and over | 1,259 | 1,551 | +23% |
| Women | 00-04 years | 248 | 146 | -41% |
| Women | 05-09 years | 429 | 271 | -37% |
| Women | 10-14 years | 1,403 | 1,224 | -13% |
| Women | 15-17 years | 2,948 | 2,738 | -7% |
| Women | 18-19 years | 4,075 | 3,872 | -5% |
| Women | 20-24 years | 5,403 | 4,775 | -12% |
| Women | 25-29 years | 5,339 | 5,129 | -4% |
| Women | 30-34 years | 4,968 | 5,094 | +3% |
| Women | 35-39 years | 4,937 | 4,783 | -3% |
| Women | 40-44 years | 4,834 | 4,493 | -7% |
| Women | 45-49 years | 4,338 | 4,349 | +0% |
| Women | 50-54 years | 3,598 | 4,162 | +16% |
| Women | 55-59 years | 2,844 | 3,472 | +22% |
| Women | 60-64 years | 2,159 | 2,715 | +26% |
| Women | 65-69 years | 1,762 | 2,162 | +23% |
| Women | 70-74 years | 1,361 | 1,777 | +31% |
| Women | 75 years and over | 1,008 | 1,304 | +29% |
| Men | 00-04 years | 228 | 139 | -39% |
| Men | 05-09 years | 462 | 291 | -37% |
| Men | 10-14 years | 1,138 | 1,125 | -1% |
| Men | 15-17 years | 2,203 | 2,570 | +17% |
| Men | 18-19 years | 4,160 | 3,963 | -5% |
| Men | 20-24 years | 5,667 | 5,234 | -8% |
| Men | 25-29 years | 6,581 | 5,925 | -10% |
| Men | 30-34 years | 6,609 | 6,049 | -8% |
| Men | 35-39 years | 6,098 | 5,906 | -3% |
| Men | 40-44 years | 6,011 | 5,646 | -6% |
| Men | 45-49 years | 5,761 | 5,427 | -6% |
| Men | 50-54 years | 5,244 | 5,454 | +4% |
| Men | 55-59 years | 4,485 | 4,809 | +7% |
| Men | 60-64 years | 3,821 | 4,269 | +12% |
| Men | 65-69 years | 3,093 | 3,507 | +13% |
| Men | 70-74 years | 2,403 | 2,716 | +13% |
| Men | 75 years and over | 1,564 | 1,846 | +18% |
Chart 1 compares only two years, so Chart 2 checks whether the split is a steady trend or a one-off. It groups people into eight age bands and follows each band every year from 2017 to 2026. In the default view, each line is indexed to its own 2017 level (2017 = 100), so a line above 100 means that band is now more likely to be victimised than it was in 2017, however high or low its rate started. Every band dipped during the COVID-19 lockdown years, when many types of crime fell. As restrictions lifted, the bands separated. The three oldest bands, shown in colour, were back above their 2017 levels by 2024 and kept climbing to a peak in 2025, while most younger bands, shown in grey, only recovered to around where they started. By 2026, the 75+ band sat at 123, the 65–74 band at 116 and the 55–64 band at 114, compared with 91 for 18–24 year olds. The “Actual rates” button keeps the comparison honest. In absolute terms, 18–24 year olds still had a rate of 4,723 per 100,000 in 2026, against 1,551 for people aged 75 and over. The story is not that older Victorians face the most crime, but that they are the only group whose risk is growing.
older_bands <- c("55–64", "65–74", "75+")
band_cols <- c("0–17" = "#C9C9C9", "18–24" = "#B5B5B5", "25–34" = "#A1A1A1",
"35–44" = "#8D8D8D", "45–54" = "#797979",
"55–64" = "#E69F00", "65–74" = "#D55E00", "75+" = "#8B2F00")
c2 <- pop_band |>
filter(sex == "People") |>
group_by(band) |>
mutate(index = rate / rate[year == 2017] * 100) |>
ungroup() |>
mutate(tip = paste0("<b>Aged ", band, "</b> (", year, ")<br>Rate: ", fmt(rate),
" per 100,000<br>Index: ", fmt(index), " (2017 = 100)"))
views2 <- list(
index = list(col = "index", label = "Change since 2017",
ytitle = "Index (2017 = 100)",
title = "<b>Since 2017, the three oldest age bands have pulled away from everyone else</b><br><sup>Victimisation rate indexed to 2017 = 100, by age band</sup>"),
rate = list(col = "rate", label = "Actual rates",
ytitle = "Victim reports per 100,000 people",
title = "<b>Older Victorians are still victimised less often, but the gap is closing</b><br><sup>Victim reports per 100,000 people, by age band</sup>"))
end_labels <- function(v) {
d <- filter(c2, year == 2026, band %in% older_bands)
lapply(seq_len(nrow(d)), function(i) {
list(x = 2026, y = d[[v]][i], text = paste0("<b>", d$band[i], "</b>"), xanchor = "left",
xshift = 6, showarrow = FALSE, font = list(color = band_cols[[as.character(d$band[i])]], size = 12))
})
}
ref_line <- list(type = "line", xref = "paper", x0 = 0, x1 = 1, y0 = 100, y1 = 100,
line = list(color = "#444444", dash = "dot", width = 1))
src2 <- src_note("Crime Statistics Agency (2026), Victim Reports, Table 02. Rates for age bands derived (see Notes).")
p2 <- plot_ly(); grp2 <- character()
for (v in names(views2)) {
for (b in band_levels) {
d <- filter(c2, band == b)
is_old <- b %in% older_bands
p2 <- add_trace(p2, data = d, x = ~year, y = d[[views2[[v]]$col]],
type = "scatter", mode = "lines+markers", name = b, legendgroup = b,
showlegend = (v == "index"), visible = (v == "index"),
text = ~tip, hoverinfo = "text",
line = list(color = band_cols[[b]], width = ifelse(is_old, 3.5, 1.8)),
marker = list(color = band_cols[[b]], size = ifelse(is_old, 6, 4)))
grp2 <- c(grp2, v)
}
}
buttons2 <- lapply(names(views2), function(v) {
list(method = "update", label = views2[[v]]$label,
args = list(list(visible = grp2 == v, showlegend = grp2 == v),
list(title = list(text = views2[[v]]$title, x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top"),
`yaxis.title.text` = views2[[v]]$ytitle,
shapes = if (v == "index") list(ref_line) else list(),
annotations = c(end_labels(views2[[v]]$col), list(src2)))))
})
p2 |>
layout(
title = list(text = views2$index$title, x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top"), font = font_main,
xaxis = list(title = "Year ending June", dtick = 1, range = c(2016.6, 2026.9)),
yaxis = list(title = views2$index$ytitle),
shapes = list(ref_line),
annotations = c(end_labels("index"), list(src2)),
updatemenus = list(list(type = "buttons", direction = "right", buttons = buttons2,
x = 0, xanchor = "left", y = 1.02, yanchor = "bottom",
bgcolor = "#F4F4F4", bordercolor = "#BBBBBB")),
legend = list(title = list(text = "<b>Age band</b>")),
hovermode = "closest",
margin = list(t = 150, b = 100)
) |>
tidy_config()
Chart description: a line chart from 2017 to 2026 with one line per age band. In the default “Change since 2017” view, every line starts at 100; the 55–64, 65–74 and 75+ lines (orange to dark red) finish well above 100, while the grey younger bands finish at or below it. The “Actual rates” button shows the underlying rates, where younger adults remain highest but the older bands are rising.
| Age band | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 |
|---|---|---|---|---|---|---|---|---|---|---|
| 0–17 | 932 | 925 | 879 | 865 | 862 | 868 | 974 | 1,000 | 969 | 905 |
| 18–24 | 5,175 | 4,742 | 4,697 | 4,848 | 4,368 | 4,066 | 4,210 | 4,431 | 5,009 | 4,723 |
| 25–34 | 5,871 | 5,347 | 5,192 | 5,447 | 4,986 | 4,743 | 4,886 | 5,211 | 6,079 | 5,554 |
| 35–44 | 5,469 | 4,871 | 4,747 | 4,948 | 4,295 | 4,071 | 4,440 | 4,856 | 5,677 | 5,208 |
| 45–54 | 4,742 | 4,284 | 4,246 | 4,491 | 3,901 | 3,698 | 4,044 | 4,377 | 5,292 | 4,843 |
| 55–64 | 3,341 | 3,106 | 3,052 | 3,202 | 2,775 | 2,689 | 2,986 | 3,412 | 4,088 | 3,811 |
| 65–74 | 2,180 | 2,022 | 1,959 | 2,118 | 1,720 | 1,721 | 2,031 | 2,226 | 2,666 | 2,538 |
| 75+ | 1,259 | 1,123 | 1,144 | 1,321 | 1,102 | 1,071 | 1,241 | 1,414 | 1,639 | 1,551 |
Chart 3 asks what kinds of crime are behind the rise. Each bar shows how much the victimisation rate for one offence type changed between 2017 and 2026, after allowing for population growth: orange bars are increases and blue bars are decreases. The chart opens on Victorians aged 75 and over, and the menu lets you switch to any other age band for comparison. For the oldest group, deception (fraud, scams and similar offences) stands out, with its rate up 320%, more than four times its 2017 level. Stalking, harassment and threats rose 72%, assault 57% and theft 29%. These are offences that can happen over the phone, online or through people the victim knows, rather than on the street. Burglary is the one major offence that fell, but even here the oldest group benefited least: the 75+ burglary rate fell 17%, compared with a fall of 45% for people aged 25–34. Switching to younger bands shows a different picture, with smaller rises and much larger falls. Offence types with fewer than 50 reports in 2017 for a band are left out, because percentage changes on very small numbers can be misleading.
c3 <- offence_rates |>
filter(sex == "People", year %in% c(2017, 2026)) |>
select(band, offence, year, reports, rate) |>
pivot_wider(names_from = year, values_from = c(reports, rate)) |>
filter(reports_2017 >= 50) |> # avoid misleading % changes on tiny bases
mutate(change = (rate_2026 / rate_2017 - 1) * 100,
tip = paste0("<b>", offence, "</b><br>Rate 2017: ", fmt(rate_2017, 1),
" → 2026: ", fmt(rate_2026, 1), " per 100,000",
"<br>Reports: ", fmt(reports_2017), " → ", fmt(reports_2026),
"<br>Change in rate: ", sgn(change), fmt(change), "%"))
offence_order <- c3 |> filter(band == "75+") |> arrange(change) |> pull(offence)
offence_order <- c(setdiff(unique(c3$offence), offence_order), offence_order)
c3_title <- function(b) list(
text = paste0("<b>What changed for Victorians aged ", b, "?</b>",
"<br><sup>% change in victimisation rate per 100,000, by offence type, 2017 to 2026</sup>"),
x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top")
menu_bands <- c("75+", "65–74", "55–64", "45–54", "35–44", "25–34", "18–24", "0–17")
p3 <- plot_ly()
for (i in seq_along(menu_bands)) {
d <- filter(c3, band == menu_bands[i])
p3 <- add_bars(p3, data = d, x = ~change, y = ~offence, orientation = "h",
name = menu_bands[i], visible = (i == 1),
marker = list(color = ifelse(d$change >= 0, col_rise, col_fall)),
text = ~tip, hoverinfo = "text", textposition = "none")
}
buttons3 <- lapply(seq_along(menu_bands), function(i) {
list(method = "update", label = paste("Aged", menu_bands[i]),
args = list(list(visible = seq_along(menu_bands) == i),
list(title = c3_title(menu_bands[i]))))
})
p3 |>
layout(
title = c3_title("75+"), font = font_main, showlegend = FALSE,
xaxis = list(title = "% change in rate, 2017 to 2026", ticksuffix = "%", zeroline = TRUE,
zerolinecolor = "#444444", zerolinewidth = 1.5),
yaxis = list(title = "", categoryorder = "array", categoryarray = offence_order),
annotations = list(src_note("Crime Statistics Agency (2026), Victim Reports, Tables 02 and 04. Rates derived (see Notes).")),
updatemenus = list(list(buttons = buttons3, x = 0, xanchor = "left", y = 1.02,
yanchor = "bottom", bgcolor = "#F4F4F4", bordercolor = "#BBBBBB")),
margin = list(t = 150, l = 10, b = 100)
) |>
tidy_config()
Chart description: a horizontal bar chart of percentage change in victimisation rate for each offence type, with a menu to choose the age band. For the 75+ band, deception rises by several hundred per cent, and stalking, assault, theft and property damage all rise (orange bars), while burglary falls (blue bar). Choosing younger bands shows smaller rises and larger falls, especially for burglary.
| Age band | Offence type | Reports 2017 | Reports 2026 | Rate 2017 | Rate 2026 | Change in rate |
|---|---|---|---|---|---|---|
| 75+ | Deception (fraud, scams) | 132 | 767 | 31.2 | 131.0 | +320% |
| 75+ | Stalking, harassment & threats | 68 | 162 | 16.1 | 27.7 | +72% |
| 75+ | Assault | 348 | 757 | 82.2 | 129.3 | +57% |
| 75+ | Theft | 2,336 | 4,181 | 551.6 | 714.3 | +29% |
| 75+ | Arson & property damage | 684 | 1,163 | 161.5 | 198.7 | +23% |
| 75+ | Sexual offences | 71 | 101 | 16.8 | 17.3 | +3% |
| 75+ | Other crimes against the person | 73 | 94 | 17.2 | 16.1 | -7% |
| 75+ | Burglary / break and enter | 1,620 | 1,853 | 382.6 | 316.6 | -17% |
| 65–74 | Deception (fraud, scams) | 191 | 906 | 35.9 | 139.7 | +289% |
| 65–74 | Assault | 889 | 1,792 | 167.1 | 276.3 | +65% |
| 65–74 | Sexual offences | 83 | 128 | 15.6 | 19.7 | +27% |
| 65–74 | Theft | 5,516 | 8,326 | 1,036.5 | 1,283.6 | +24% |
| 65–74 | Arson & property damage | 1,693 | 2,396 | 318.1 | 369.4 | +16% |
| 65–74 | Stalking, harassment & threats | 243 | 323 | 45.7 | 49.8 | +9% |
| 65–74 | Other crimes against the person | 146 | 142 | 27.4 | 21.9 | -20% |
| 65–74 | Burglary / break and enter | 2,837 | 2,445 | 533.1 | 376.9 | -29% |
| 55–64 | Deception (fraud, scams) | 336 | 1,370 | 47.7 | 174.9 | +267% |
| 55–64 | Assault | 2,499 | 4,094 | 354.5 | 522.8 | +47% |
| 55–64 | Sexual offences | 268 | 415 | 38.0 | 53.0 | +39% |
| 55–64 | Stalking, harassment & threats | 545 | 816 | 77.3 | 104.2 | +35% |
| 55–64 | Theft | 11,299 | 14,920 | 1,602.9 | 1,905.3 | +19% |
| 55–64 | Arson & property damage | 3,454 | 4,204 | 490.0 | 536.8 | +10% |
| 55–64 | Other crimes against the person | 308 | 373 | 43.7 | 47.6 | +9% |
| 55–64 | Burglary / break and enter | 4,834 | 3,633 | 685.8 | 463.9 | -32% |
| 45–54 | Deception (fraud, scams) | 503 | 1,762 | 62.1 | 205.4 | +230% |
| 45–54 | Sexual offences | 703 | 895 | 86.9 | 104.3 | +20% |
| 45–54 | Assault | 5,823 | 7,102 | 719.5 | 827.7 | +15% |
| 45–54 | Stalking, harassment & threats | 1,178 | 1,382 | 145.5 | 161.1 | +11% |
| 45–54 | Theft | 17,590 | 19,848 | 2,173.4 | 2,313.2 | +6% |
| 45–54 | Arson & property damage | 5,439 | 5,628 | 672.0 | 655.9 | -2% |
| 45–54 | Other crimes against the person | 645 | 635 | 79.7 | 74.0 | -7% |
| 45–54 | Burglary / break and enter | 6,496 | 4,273 | 802.6 | 498.0 | -38% |
| 35–44 | Deception (fraud, scams) | 671 | 2,321 | 79.1 | 217.5 | +175% |
| 35–44 | Sexual offences | 908 | 1,627 | 107.0 | 152.4 | +43% |
| 35–44 | Assault | 7,884 | 10,573 | 928.8 | 990.7 | +7% |
| 35–44 | Stalking, harassment & threats | 1,563 | 1,957 | 184.1 | 183.4 | 0% |
| 35–44 | Theft | 21,110 | 26,289 | 2,487.1 | 2,463.3 | -1% |
| 35–44 | Other crimes against the person | 910 | 1,083 | 107.2 | 101.5 | -5% |
| 35–44 | Arson & property damage | 5,685 | 6,479 | 669.8 | 607.1 | -9% |
| 35–44 | Burglary / break and enter | 7,683 | 5,220 | 905.2 | 489.1 | -46% |
| 25–34 | Deception (fraud, scams) | 1,032 | 2,522 | 104.6 | 229.8 | +120% |
| 25–34 | Sexual offences | 1,189 | 2,702 | 120.5 | 246.2 | +104% |
| 25–34 | Assault | 10,650 | 12,192 | 1,079.0 | 1,110.8 | +3% |
| 25–34 | Stalking, harassment & threats | 1,819 | 2,027 | 184.3 | 184.7 | +0% |
| 25–34 | Theft | 28,488 | 29,804 | 2,886.3 | 2,715.5 | -6% |
| 25–34 | Arson & property damage | 5,722 | 5,704 | 579.7 | 519.7 | -10% |
| 25–34 | Other crimes against the person | 1,504 | 1,378 | 152.4 | 125.6 | -18% |
| 25–34 | Burglary / break and enter | 7,534 | 4,603 | 763.3 | 419.4 | -45% |
| 18–24 | Deception (fraud, scams) | 648 | 1,553 | 104.4 | 233.6 | +124% |
| 18–24 | Sexual offences | 1,293 | 2,435 | 208.3 | 366.3 | +76% |
| 18–24 | Stalking, harassment & threats | 989 | 1,063 | 159.3 | 159.9 | +0% |
| 18–24 | Assault | 7,000 | 6,907 | 1,127.4 | 1,039.0 | -8% |
| 18–24 | Theft | 15,116 | 14,532 | 2,434.6 | 2,185.9 | -10% |
| 18–24 | Other crimes against the person | 1,285 | 1,001 | 207.0 | 150.6 | -27% |
| 18–24 | Arson & property damage | 3,259 | 2,417 | 524.9 | 363.6 | -31% |
| 18–24 | Burglary / break and enter | 2,541 | 1,476 | 409.3 | 222.0 | -46% |
| 0–17 | Deception (fraud, scams) | 64 | 146 | 4.7 | 9.8 | +110% |
| 0–17 | Other crimes against the person | 823 | 1,250 | 59.8 | 83.8 | +40% |
| 0–17 | Arson & property damage | 179 | 215 | 13.0 | 14.4 | +11% |
| 0–17 | Stalking, harassment & threats | 462 | 515 | 33.6 | 34.5 | +3% |
| 0–17 | Theft | 1,666 | 1,854 | 121.1 | 124.3 | +3% |
| 0–17 | Sexual offences | 3,382 | 3,468 | 245.8 | 232.5 | -5% |
| 0–17 | Assault | 6,034 | 5,886 | 438.5 | 394.6 | -10% |
| 0–17 | Burglary / break and enter | 210 | 160 | 15.3 | 10.7 | -30% |
Because deception showed the biggest jump in Chart 3, Chart 4 looks at it in detail across every age band and every year. Each cell of the heatmap is one age band in one year. Brighter yellow means a higher value and darker purple a lower one, using a colour scale that stays readable for people with colour-vision deficiency. In the default “Growth since 2017” view, each cell shows the deception rate as a multiple of that band’s own 2017 rate, so the comparison is about how fast each group’s risk has grown. Deception has risen in every age group, but the growth gets steeper with age. For 25–34 year olds, the 2026 rate was 2.2 times the 2017 rate; for people aged 75 and over, it was 4.2 times. The “Actual rates” view shows the other half of the story. Working-age adults still report the most deception in absolute terms, with 230 victims per 100,000 people aged 25–34 in 2026, compared with 131 among those aged 75 and over. Older Victorians started from a much lower base, but they are catching up the fastest.
c4 <- offence_rates |>
filter(sex == "People", offence == "Deception (fraud, scams)") |>
group_by(band) |>
mutate(mult = rate / rate[year == 2017]) |>
ungroup() |>
mutate(tip = paste0("<b>Aged ", band, ", ", year, "</b><br>", fmt(rate, 1),
" per 100,000 (", fmt(reports), " victim reports)<br>",
fmt(mult, 1), "× the 2017 rate"))
c4_titles <- list(
mult = "<b>Deception has grown fastest among the oldest Victorians</b><br><sup>Deception victimisation rate as a multiple of each age band's 2017 rate</sup>",
rate = "<b>In absolute terms, working-age adults still report the most deception</b><br><sup>Victims of deception offences per 100,000 people, by age band and year</sup>")
p4 <- plot_ly() |>
add_trace(data = c4, x = ~year, y = ~band, z = ~mult, type = "heatmap",
colorscale = "Viridis", text = ~tip, hoverinfo = "text", visible = TRUE,
colorbar = list(title = list(text = "× 2017<br>rate"))) |>
add_trace(data = c4, x = ~year, y = ~band, z = ~rate, type = "heatmap",
colorscale = "Viridis", text = ~tip, hoverinfo = "text", visible = FALSE,
colorbar = list(title = list(text = "Rate per<br>100,000")))
buttons4 <- list(
list(method = "update", label = "Growth since 2017",
args = list(list(visible = c(TRUE, FALSE)),
list(title = list(text = c4_titles$mult, x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top")))),
list(method = "update", label = "Actual rates",
args = list(list(visible = c(FALSE, TRUE)),
list(title = list(text = c4_titles$rate, x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top")))))
p4 |>
layout(
title = list(text = c4_titles$mult, x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top"), font = font_main,
xaxis = list(title = "Year ending June", dtick = 1),
yaxis = list(title = "Age band", categoryorder = "array", categoryarray = band_levels),
annotations = list(src_note("Crime Statistics Agency (2026), Victim Reports, Tables 02 and 04. Rates derived (see Notes).")),
updatemenus = list(list(type = "buttons", direction = "right", buttons = buttons4,
x = 0, xanchor = "left", y = 1.02, yanchor = "bottom",
bgcolor = "#F4F4F4", bordercolor = "#BBBBBB")),
margin = list(t = 150, b = 100)
) |>
tidy_config()
Chart description: a heatmap with years across and age bands down, using a colour-blind-safe purple-to-yellow scale. In the default “Growth since 2017” view, the oldest bands in the bottom rows turn the brightest yellow by 2026, showing the largest growth. The “Actual rates” view shows working-age bands with the highest absolute rates.
| Age band | 2017 | 2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 |
|---|---|---|---|---|---|---|---|---|---|---|
| 0–17 | 4.7 | 6.6 | 6.2 | 7.8 | 9.3 | 7.4 | 9.6 | 10.1 | 10.6 | 9.8 |
| 18–24 | 104.4 | 175.2 | 190.6 | 235.8 | 239.0 | 178.5 | 205.4 | 205.4 | 201.8 | 233.6 |
| 25–34 | 104.6 | 178.1 | 209.2 | 242.7 | 253.5 | 197.9 | 229.1 | 228.1 | 216.2 | 229.8 |
| 35–44 | 79.1 | 130.5 | 169.6 | 189.3 | 197.3 | 173.8 | 205.0 | 195.7 | 189.0 | 217.5 |
| 45–54 | 62.1 | 102.2 | 123.0 | 154.1 | 164.9 | 144.2 | 184.7 | 183.1 | 187.4 | 205.4 |
| 55–64 | 47.7 | 76.1 | 104.4 | 115.0 | 126.8 | 111.0 | 155.6 | 146.4 | 152.4 | 174.9 |
| 65–74 | 35.9 | 53.3 | 80.6 | 79.7 | 93.7 | 83.4 | 139.7 | 124.3 | 133.3 | 139.7 |
| 75+ | 31.2 | 35.0 | 60.0 | 62.7 | 80.4 | 69.1 | 103.1 | 101.9 | 99.4 | 131.0 |
The final chart asks who within the older population is most affected, by comparing women and men directly. Each row is an age band. The orange circle shows the percentage change in the victimisation rate for women between 2017 and 2026, the blue diamond shows the same for men, and the grey line between them shows the size of the gap. Points to the right of the zero line mean the rate rose. Across all offences, both sexes follow the turning point seen in Chart 1, but from age 45 onwards the increase is larger for women in every band. Among Victorians aged 75 and over, the rate rose 29% for women compared with 18% for men. The menu breaks this down by offence type, and two offences stand out. Deception among women aged 75 and over rose 390%, compared with 257% for men of the same age. For sexual offences, the rate for women aged 55–64 rose 82%, while for men of the same age it fell 24%. Groups with fewer than 30 reports in 2017 are not shown, because changes based on very small numbers are unreliable.
# All offences (Table 02 rates) plus each offence type (Table 04 derived rates), by sex
c5_all <- bind_rows(
pop_band |> mutate(option = "All offences"),
offence_rates |> rename(option = offence)
) |>
filter(sex %in% c("Females", "Males"), year %in% c(2017, 2026)) |>
select(option, sex, band, year, reports, rate) |>
pivot_wider(names_from = year, values_from = c(reports, rate)) |>
mutate(change = ifelse(reports_2017 >= 30, (rate_2026 / rate_2017 - 1) * 100, NA),
who = ifelse(sex == "Females", "Women", "Men"),
tip = paste0("<b>", who, ", aged ", band, "</b><br>", option,
"<br>Rate 2017: ", fmt(rate_2017, 1), " → 2026: ", fmt(rate_2026, 1),
" per 100,000<br>Change: ", sgn(change), fmt(change), "%"))
options5 <- c("All offences", "Deception (fraud, scams)", "Assault", "Sexual offences",
"Stalking, harassment & threats", "Theft", "Arson & property damage",
"Burglary / break and enter")
c5_title <- function(o) {
headline <- if (o == "All offences") {
"<b>From 45 onwards, women's victimisation rates are rising faster than men's</b>"
} else {
paste0("<b>Women vs men: change in victimisation rate for ", tolower(o), "</b>")
}
list(text = paste0(headline, "<br><sup>% change in rate per 100,000, 2017 to 2026, by sex and age band",
if (o == "All offences") ", all offences" else "", "</sup>"),
x = 0, xanchor = "left", y = 0.97, yref = "container", yanchor = "top")
}
p5 <- plot_ly(); grp5 <- character()
for (o in options5) {
d <- filter(c5_all, option == o)
dw <- d |> select(band, who, change) |> pivot_wider(names_from = who, values_from = change) |>
filter(!is.na(Women), !is.na(Men))
vis <- (o == "All offences")
if (nrow(dw) > 0) {
p5 <- add_segments(p5, data = dw, x = ~Women, xend = ~Men, y = ~band, yend = ~band,
line = list(color = "#CCCCCC", width = 3), showlegend = FALSE,
hoverinfo = "none", visible = vis)
grp5 <- c(grp5, o)
}
dF <- filter(d, sex == "Females", !is.na(change))
dM <- filter(d, sex == "Males", !is.na(change))
if (nrow(dF) > 0) {
p5 <- add_markers(p5, data = dF, x = ~change, y = ~band,
name = "Women", legendgroup = "Women", visible = vis,
marker = list(color = col_women, size = 12, symbol = "circle"),
text = ~tip, hoverinfo = "text")
grp5 <- c(grp5, o)
}
if (nrow(dM) > 0) {
p5 <- add_markers(p5, data = dM, x = ~change, y = ~band,
name = "Men", legendgroup = "Men", visible = vis,
marker = list(color = col_men, size = 12, symbol = "diamond"),
text = ~tip, hoverinfo = "text")
grp5 <- c(grp5, o)
}
}
buttons5 <- lapply(options5, function(o) {
list(method = "update", label = o,
args = list(list(visible = grp5 == o),
list(title = c5_title(o), `xaxis.autorange` = TRUE)))
})
p5 |>
layout(
title = c5_title("All offences"), font = font_main,
xaxis = list(title = "% change in rate, 2017 to 2026", ticksuffix = "%",
zeroline = TRUE, zerolinecolor = "#444444", zerolinewidth = 1.5),
yaxis = list(title = "Age band", categoryorder = "array", categoryarray = band_levels),
annotations = list(src_note("Crime Statistics Agency (2026), Victim Reports, Tables 02 and 04. Groups with fewer than 30 reports in 2017 are not shown.")),
updatemenus = list(list(buttons = buttons5, x = 0, xanchor = "left", y = 1.02,
yanchor = "bottom", bgcolor = "#F4F4F4", bordercolor = "#BBBBBB")),
legend = list(orientation = "h", x = 1, xanchor = "right", y = 1.02, yanchor = "bottom"),
margin = list(t = 150, b = 110)
) |>
tidy_config()
Chart description: a dot plot with one row per age band and two markers per row, an orange circle for women and a blue diamond for men, showing the percentage change in victimisation rate. A menu switches between all offences and individual offence types. For all offences, most markers under 45 sit left of zero (decreases); from 45 upwards both sit right of zero, with the women’s circle further right. Groups with fewer than 30 reports in 2017 are not shown.
| Offence type | Age band | Women: change | Men: change |
|---|---|---|---|
| All offences | 0–17 | -9% | +4% |
| All offences | 18–24 | -11% | -7% |
| All offences | 25–34 | -1% | -9% |
| All offences | 35–44 | -5% | -5% |
| All offences | 45–54 | +7% | -1% |
| All offences | 55–64 | +23% | +9% |
| All offences | 65–74 | +25% | +13% |
| All offences | 75+ | +29% | +18% |
| Deception (fraud, scams) | 0–17 | +42% | +183% |
| Deception (fraud, scams) | 18–24 | +108% | +137% |
| Deception (fraud, scams) | 25–34 | +123% | +117% |
| Deception (fraud, scams) | 35–44 | +171% | +180% |
| Deception (fraud, scams) | 45–54 | +259% | +209% |
| Deception (fraud, scams) | 55–64 | +266% | +266% |
| Deception (fraud, scams) | 65–74 | +295% | +286% |
| Deception (fraud, scams) | 75+ | +390% | +257% |
| Assault | 0–17 | -11% | -9% |
| Assault | 18–24 | -7% | -9% |
| Assault | 25–34 | +9% | -4% |
| Assault | 35–44 | +13% | -1% |
| Assault | 45–54 | +22% | +8% |
| Assault | 55–64 | +58% | +40% |
| Assault | 65–74 | +77% | +59% |
| Assault | 75+ | +53% | +63% |
| Sexual offences | 0–17 | -6% | -3% |
| Sexual offences | 18–24 | +62% | +186% |
| Sexual offences | 25–34 | +95% | +182% |
| Sexual offences | 35–44 | +46% | +20% |
| Sexual offences | 45–54 | +39% | -27% |
| Sexual offences | 55–64 | +82% | -24% |
| Sexual offences | 65–74 | +64% | -16% |
| Sexual offences | 75+ | +17% | n/a (small numbers) |
| Stalking, harassment & threats | 0–17 | -14% | +37% |
| Stalking, harassment & threats | 18–24 | -3% | +10% |
| Stalking, harassment & threats | 25–34 | +1% | -2% |
| Stalking, harassment & threats | 35–44 | +1% | -3% |
| Stalking, harassment & threats | 45–54 | +11% | +11% |
| Stalking, harassment & threats | 55–64 | +43% | +27% |
| Stalking, harassment & threats | 65–74 | +13% | +7% |
| Stalking, harassment & threats | 75+ | +72% | +71% |
| Theft | 0–17 | -16% | +12% |
| Theft | 18–24 | -16% | -7% |
| Theft | 25–34 | -3% | -8% |
| Theft | 35–44 | -3% | +0% |
| Theft | 45–54 | +14% | +2% |
| Theft | 55–64 | +34% | +12% |
| Theft | 65–74 | +34% | +21% |
| Theft | 75+ | +36% | +24% |
| Arson & property damage | 0–17 | -15% | +43% |
| Arson & property damage | 18–24 | -36% | -24% |
| Arson & property damage | 25–34 | -13% | -8% |
| Arson & property damage | 35–44 | -13% | -6% |
| Arson & property damage | 45–54 | -2% | -2% |
| Arson & property damage | 55–64 | +10% | +10% |
| Arson & property damage | 65–74 | +23% | +12% |
| Arson & property damage | 75+ | +36% | +13% |
| Burglary / break and enter | 0–17 | -38% | -23% |
| Burglary / break and enter | 18–24 | -51% | -40% |
| Burglary / break and enter | 25–34 | -44% | -46% |
| Burglary / break and enter | 35–44 | -52% | -41% |
| Burglary / break and enter | 45–54 | -41% | -36% |
| Burglary / break and enter | 55–64 | -31% | -32% |
| Burglary / break and enter | 65–74 | -25% | -31% |
| Burglary / break and enter | 75+ | -13% | -21% |
Victoria is ageing, and its oldest residents are the one group for whom the crime picture is getting worse rather than better. The offences behind that rise, especially fraud and scams, assault, and stalking and harassment, can be less visible than street crime. They can happen over the phone, online, or at the hands of someone the victim knows. With Victorians heading to a state election in November 2026, the data suggests a question worth asking of every party: what is the plan for keeping older Victorians safe?
Anthropic. (2026). Claude (Opus 5.5 version) [Large language model]. https://claude.ai
Crime Statistics Agency. (2026). Victim reports: Data tables, year ending June 2026 [Data set]. Victorian Government. https://files.crimestatistics.vic.gov.au/2026-09/Data_Tables_Victim_Reports_Visualisation_Year_Ending_June_2026.xlsx
Okabe, M., & Ito, K. (2008). Color universal design (CUD): How to make figures and presentations that are friendly to colorblind people. J*Fly. https://jfly.uni-koeln.de/color/
R Core Team. (2026). R: A language and environment for statistical computing [Computer software]. R Foundation for Statistical Computing. https://www.R-project.org/
Sievert, C. (2020). Interactive web-based data visualization with R, plotly, and shiny. Chapman and Hall/CRC. https://plotly-r.com
Wickham, H., Averick, M., Bryan, J., Chang, W., McGowan, L. D., François, R., Grolemund, G., Hayes, A., Henry, L., Hester, J., Kuhn, M., Pedersen, T. L., Miller, E., Bache, S. M., Müller, K., Ooms, J., Robinson, D., Seidel, D. P., Spinu, V., … Yutani, H. (2019). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686. https://doi.org/10.21105/joss.01686
Data for this piece came from the Crime Statistics Agency’s Victim Reports data tables for the year ending June 2026, published on the Victorian Government’s DataVic portal under a Creative Commons Attribution 4.0 International (CC BY 4.0) licence. The report was written and rendered in R Markdown using the readxl, dplyr, tidyr, plotly and knitr packages, published on RPubs, and submitted via Cadmus.
I used Claude (Anthropic, 2026) to help explore the data, draft and debug the R code for the charts, suggest wording for the narrative, and check the report against the marking rubric. I reviewed, ran and checked all code and figures against the source data, and edited the text in my own words.