VICTORIAN RECORDED OFFENCES · 2017–2026
620,140
offences were recorded across Victoria’s 79 LGAs in the year ending June 2026
2.2% fewer than 2025, while the population-adjusted rate fell 3.9%.

The headline improved, but the story did not simply reverse

In Victoria, the number of offences reported during the year ending June 2026 had decreased compared to the last year. It is positive news following the spike in offences seen in 2025; however, the latest rate was still higher than that of 2024 and even 2017. The decrease was also not consistent, as some offence types were still increasing.

The report was created for the people of Victoria, whether they are looking to live, study, and/or visit somewhere. The report does not mark any community as either safe or unsafe. Rather, it distinguishes between numbers and rates, and follows the state narrative in terms of time, offence, geography, location, and investigation status.

1. A decade’s perspective gives meaning to the recent decline

state_annual <- state_annual %>%
  mutate(
    hover = paste0(
      "Year ending June ", Year,
      "<br>Recorded offences: ", comma(offences),
      "<br>Rate: ", comma(rate, accuracy = 0.1), " per 100,000"
    )
  )

p1 <- ggplot(
  state_annual,
  aes(x = Year, y = rate, text = hover, group = 1)
) +
  geom_line(colour = blue, linewidth = 1.2) +
  geom_point(aes(colour = Year == latest_year), size = 3.5) +
  scale_colour_manual(values = c(`FALSE` = blue, `TRUE` = orange), guide = "none") +
  scale_x_continuous(breaks = state_annual$Year) +
  scale_y_continuous(
    labels = comma,
    limits = c(0, NA),
    expand = expansion(mult = c(0, 0.12))
  ) +
  annotate(
    "text",
    x = latest_year,
    y = latest_rate,
    label = paste0(comma(latest_rate, accuracy = 1), " per 100,000"),
    vjust = -1.2,
    hjust = 1,
    colour = orange,
    fontface = "bold"
  ) +
  labs(
    title = "The 2025 spike eased, but the rate remains elevated",
    subtitle = "Recorded-offence rate per 100,000 residents, year ending June",
    x = NULL,
    y = "Offences per 100,000 residents",
    caption = source_note
  ) +
  theme_story()

w1 <- ggplotly(p1, tooltip = "text") %>%
  layout(hovermode = "x unified") %>%
  config(displaylogo = FALSE, modeBarButtonsToRemove = c("lasso2d", "select2d"))

accessible_widget(
  w1,
  "Interactive line chart of Victoria's recorded-offence rate from 2017 to 2026. The rate fell after peaking in 2025 but remained above 2024 and 2017."
)

Interactive line chart of Victoria's recorded-offence rate from 2017 to 2026. The rate fell after peaking in 2025 but remained above 2024 and 2017.

What changed? The rate fell from 8,965.9 to 8,618.3 per 100,000 between 2025 and 2026. However, it remained 2.5% above 2017 and 8.9% above 2024. One improved year therefore does not establish a long-term decline.

2. Property offences fell, but other pressures kept rising

How to read: Grey dots represent 2017. Orange represents offence divisions that increased by 2026, while teal represents divisions that decreased.

division_change <- table_02 %>%
  filter(`Year ending` == "June", Year %in% c(2017, latest_year)) %>%
  group_by(Year, `Offence Division`) %>%
  summarise(offences = sum(`Offence Count`, na.rm = TRUE), .groups = "drop") %>%
  pivot_wider(names_from = Year, values_from = offences, names_prefix = "y") %>%
  mutate(
    division = str_remove(`Offence Division`, "^[A-F]\\s+"),
    change_pct = (y2026 / y2017 - 1) * 100,
    direction = if_else(change_pct >= 0, "Increased", "Decreased"),
    division = reorder(division, change_pct),
    hover_2017 = paste0(
      str_to_sentence(as.character(division)),
      "<br>2017: ", comma(y2017)
    ),
    hover_2026 = paste0(
      str_to_sentence(as.character(division)),
      "<br>2026: ", comma(y2026),
      "<br>Change: ", number(change_pct, accuracy = 0.1, suffix = "%", sign = TRUE)
    )
  )

p2 <- ggplot(division_change, aes(y = division)) +
  geom_segment(
    aes(x = y2017, xend = y2026, yend = division, colour = direction),
    linewidth = 2,
    alpha = 0.65
  ) +
  geom_point(aes(x = y2017, text = hover_2017), colour = grey, size = 3.5) +
  geom_point(aes(x = y2026, colour = direction, text = hover_2026), size = 4.5) +
  scale_colour_manual(values = c("Increased" = orange, "Decreased" = teal)) +
  scale_x_continuous(labels = label_number(scale = 0.001, suffix = "k"), limits = c(0, NA)) +
  labs(
  title = "Change extended beyond property crime",
  subtitle = "Grey = 2017; orange = increased by 2026; teal = decreased by 2026",
  x = "Recorded offences",
  y = NULL,
  colour = "2017–2026",
  caption = paste(source_note, "Grey dot = 2017; coloured dot = 2026.")
) +
theme_story() +
theme(legend.position = "none")

w2 <- ggplotly(p2, tooltip = "text") %>%
  layout(hovermode = "closest") %>%
  config(displaylogo = FALSE)

accessible_widget(
  w2,
  "Interactive dumbbell chart comparing offence divisions in 2017 and 2026. Justice procedures rose the most proportionally, while public order and security offences declined."
)

Interactive dumbbell chart comparing offence divisions in 2017 and 2026. Justice procedures rose the most proportionally, while public order and security offences declined.

Property and deception offences remained the largest division in 2026, but they were 5.2% lower than in 2025. The longer view shows a different pressure: justice procedures offences were 45.0% higher than in 2017, crimes against the person were 22.1% higher, and drug offences were 14.8% higher. The statewide easing was therefore driven mainly by falling property offences, not a uniform reduction across the system.

3. Counts and rates address different queries

How to read: Blue represents metropolitan LGAs and orange represents regional LGAs. Bubble size represents estimated population.

latest_lga <- lga_annual %>%
  filter(Year == latest_year) %>%
  mutate(
    label = if_else(
      `Local Government Area` %in% c("Melbourne", "Latrobe", "Yarra"),
      `Local Government Area`,
      NA_character_
    ),
    hover = paste0(
      "<b>", `Local Government Area`, "</b>",
      "<br>", area_type, " · ", `Police Region`,
      "<br>Recorded offences: ", comma(`Offence Count`),
      "<br>Rate: ", comma(`Rate per 100,000 population`, accuracy = 0.1), " per 100,000",
      "<br>Estimated population: ", comma(estimated_population, accuracy = 1)
    )
  )

median_count <- median(latest_lga$`Offence Count`, na.rm = TRUE)
median_rate <- median(latest_lga$`Rate per 100,000 population`, na.rm = TRUE)

p3 <- ggplot(
  latest_lga,
  aes(
    x = `Offence Count`,
    y = `Rate per 100,000 population`,
    size = estimated_population,
    colour = area_type,
    text = hover
  )
) +
  geom_vline(xintercept = median_count, colour = light_grey, linetype = "dashed") +
  geom_hline(yintercept = median_rate, colour = light_grey, linetype = "dashed") +
  geom_point(alpha = 0.78) +
  geom_text(
    aes(label = label),
    size = 3.4,
    fontface = "bold",
    nudge_y = 550,
    show.legend = FALSE,
    na.rm = TRUE
  ) +
  scale_colour_manual(values = c("Metropolitan" = blue, "Regional" = orange)) +
  scale_size_area(max_size = 18, labels = comma) +
  scale_x_continuous(labels = comma, limits = c(0, NA)) +
  scale_y_continuous(labels = comma, limits = c(0, NA)) +
  labs(
  title = "High counts do not always mean high rates",
  subtitle = "Blue = metropolitan; orange = regional; bubble size = estimated population, 2026",
  x = "Recorded offences",
  y = "Offences per 100,000 residents",
  colour = "Area type",
  size = "Estimated population",
  caption = paste(
    source_note,
    "Population is inferred from the CSA count and published rate."
  )
) +
theme_story() +
theme(legend.position = "none")

w3 <- ggplotly(p3, tooltip = "text") %>%
  layout(hovermode = "closest") %>%
  config(displaylogo = FALSE)

accessible_widget(
  w3,
  "Interactive bubble chart comparing offence counts and rates across Victorian LGAs in 2026. Melbourne has the highest rate, while several regional LGAs also have high rates despite smaller counts."
)

Interactive bubble chart comparing offence counts and rates across Victorian LGAs in 2026. Melbourne has the highest rate, while several regional LGAs also have high rates despite smaller counts.

Melbourne recorded both the largest count and the highest rate, at 22,860.2 offences per 100,000. Yet the chart also reveals regional pressure: Latrobe, Mildura and Greater Shepparton had high rates with far smaller populations. Counts describe workload and volume; rates support population-adjusted comparison. Neither should be interpreted as an individual resident’s probability of experiencing crime.

4. The locations where crimes were recorded changed as well

location_annual <- table_04 %>%
  filter(`Year ending` == "June") %>%
  group_by(Year, `Location Subdivision`) %>%
  summarise(offences = sum(`Offence Count`, na.rm = TRUE), .groups = "drop")

top_locations <- location_annual %>%
  filter(Year == latest_year) %>%
  slice_max(offences, n = 10, with_ties = FALSE) %>%
  pull(`Location Subdivision`)

location_heat <- location_annual %>%
  filter(`Location Subdivision` %in% top_locations) %>%
  group_by(Year) %>%
  mutate(share = offences / sum(offences)) %>%
  ungroup() %>%
  mutate(
    location = str_remove(`Location Subdivision`, "^[0-9]+\\s+"),
    location = factor(
      location,
      levels = location_annual %>%
        filter(Year == latest_year, `Location Subdivision` %in% top_locations) %>%
        arrange(offences) %>%
        mutate(location = str_remove(`Location Subdivision`, "^[0-9]+\\s+")) %>%
        pull(location)
    ),
    hover = paste0(
      "<b>", location, "</b>",
      "<br>Year ending June ", Year,
      "<br>Offences: ", comma(offences),
      "<br>Share among the ten displayed locations: ", percent(share, accuracy = 0.1)
    )
  )

w4 <- plot_ly(
  location_heat,
  x = ~Year,
  y = ~location,
  z = ~share,
  text = ~hover,
  hoverinfo = "text",
  type = "heatmap",
  colors = viridisLite::viridis(20, option = "C"),
  colorbar = list(title = "Share", tickformat = ".0%")
) %>%
  layout(
    title = list(
      text = paste0(
        "The mix shifted away from private dwellings after 2025",
        "<br><sup>Share of offences across the ten largest location subdivisions</sup>"
      ),
      x = 0,
      xanchor = "left"
    ),
    xaxis = list(title = "Year ending June", dtick = 1),
    yaxis = list(title = ""),
    margin = list(l = 160, r = 40, b = 70, t = 90),
    annotations = list(
      list(
        text = source_note,
        x = 0,
        y = -0.18,
        xref = "paper",
        yref = "paper",
        showarrow = FALSE,
        xanchor = "left",
        font = list(size = 10, color = grey)
      )
    )
  ) %>%
  config(displaylogo = FALSE)

accessible_widget(
  w4,
  "Interactive heatmap shows the annual composition of offences across the ten largest location subdivisions from 2017 to 2026. Private dwellings remain largest, while public transport and health locations increased in 2026."
)

Interactive heatmap shows the annual composition of offences across the ten largest location subdivisions from 2017 to 2026. Private dwellings remain largest, while public transport and health locations increased in 2026.

Private dwellings remained the most common location subdivision, but offences recorded there fell by 8.2% from 2025 to 2026. Similarly, retail and street/footpaths had their offence numbers reduced. However, health locations had an increase of 27.1% in offence numbers, justice locations increased 13.2%, and public transport had an increase of 8.4%. These do not imply that those locations have been getting more dangerous.

5. The investigation status mix moved in a less reassuring direction

How to read: Teal represents arrest/summons, red represents unsolved, gold represents other, and grey represents not authorised.

status_annual <- table_05 %>%
  filter(`Year ending` == "June") %>%
  group_by(Year, `Investigation Status`) %>%
  summarise(offences = sum(`Offence Count`, na.rm = TRUE), .groups = "drop") %>%
  group_by(Year) %>%
  mutate(
    share = offences / sum(offences),
    hover = paste0(
      "<b>", `Investigation Status`, "</b>",
      "<br>Year ending June ", Year,
      "<br>Offences: ", comma(offences),
      "<br>Share: ", percent(share, accuracy = 0.1)
    )
  ) %>%
  ungroup()

status_colours <- c(
  "Arrest/Summons" = teal,
  "Unsolved" = red,
  "Other" = gold,
  "Not authorised" = grey
)

p5 <- ggplot(
  status_annual,
  aes(
    x = Year,
    y = share,
    colour = `Investigation Status`,
    text = hover,
    group = `Investigation Status`
  )
) +
  geom_line(linewidth = 1.1) +
  geom_point(size = 2.8) +
  scale_colour_manual(values = status_colours) +
  scale_x_continuous(breaks = sort(unique(status_annual$Year))) +
  scale_y_continuous(labels = percent, limits = c(0, 0.55)) +
  labs(
  title = "In 2026, 'unsolved' became the largest status",
  subtitle = "Teal = arrest/summons; red = unsolved; gold = other; grey = not authorised",
  x = NULL,
  y = "Share of recorded offences",
  colour = "Investigation status",
  caption = source_note
) +
theme_story() +
theme(legend.position = "none")

w5 <- ggplotly(p5, tooltip = "text") %>%
  layout(hovermode = "x unified") %>%
  config(displaylogo = FALSE)

accessible_widget(
  w5,
  "Interactive line chart of investigation-status shares from 2017 to 2026. In 2026, unsolved offences formed the largest share and arrest or summons declined."
)

Interactive line chart of investigation-status shares from 2017 to 2026. In 2026, unsolved offences formed the largest share and arrest or summons declined.

In 2026, 44.9% of offences reported were considered unsolved, whereas only 40.9% of offences were either arrests or summons. The number of unsolved offences increased by 2.9% from 2025 even though total offences declined, while offences resulting in arrest or summons decreased by 9.3%.

What the five views reveal

The recording rate for offences in Victoria decreased after reaching its peak in 2025, but the decrease was limited. Property and deception offences went down, but offences associated with justice processes, offences against the person, and drug offences all remained higher than their levels back in 2017. In addition, high offence levels existed in both urban and rural LGAs.

A single measurement cannot provide an entire view of the safety in a community. Numbers provide information regarding the number of crimes committed, while ratios enable comparison after considering the population size, and crime type, location, and whether they are investigated highlight additional perspectives of change. By combining all these five graphs, it is clear that the situation has improved from the 2025 peak.

Data notes and limitations

  • The analysis uses one official source: the Crime Statistics Agency Victoria workbook released on 24 September 2026.
  • Each observation is a rolling 12-month total ending in June. June snapshots are used to avoid comparing overlapping quarterly endpoints within a year.
  • “Recorded offences” depend on reporting, recording and enforcement practices. They do not represent every offence that occurred.
  • Rates per 100,000 are the Agency’s published rates. Population values shown in Chart 3 are inferred from the published counts and rates and may differ slightly because of rounding.
  • LGA rates do not measure the personal risk faced by residents. Offences may be recorded where they occur, including business, entertainment and transport areas used by non-residents.
  • The investigation status is a snapshot at the time of extraction and can change later.

Acknowledgements

I used ChatGPT (OpenAI, 2026) to debug R code, check the report structure, and for Suggesting references. I selected the Victorian crime topic and reviewed the visualisations, calculations, narrative and source data. All numerical claims were recalculated from the official Crime Statistics Agency Victoria workbook, and I take responsibility for the final submission.

References

Baglin, J. (2026). Data visualisation: From theory to practice. https://data-visualisation.stem.melbourne/

Crime Statistics Agency Victoria. (2026, September 24). Recorded offences by LGA—Year ending June 2026 [Data set]. DataVic. https://discover.data.vic.gov.au/dataset/data-tables-recorded-offences/resource/06bb24c8-8f62-4144-a746-99ef5492e4f9

OpenAI. (2026). ChatGPT [Large language model]. https://chatgpt.com/