The Problem

Narrative

Theft from motor vehicles and number plates have surged in Victoria since 2018, but not everywhere in the state is affected equally. This visualisation looks at how these thefts evolved over time and what socio-economic factors might explain the rise.


Hot Spots in 2025

SEIFA vs Crime Rate

---
title: "Plates and Parts: Victoria’s Theft Surge Since 2018"
author: "Ryan LE | s4042755"
output:
  flexdashboard::flex_dashboard:
    storyboard: true
    theme:
      version: 5
      bootswatch: flatly
    orientation: rows
    social: menu
    source_code: embed
    css: storyboard.css
---




```{r setup, include = FALSE}

library(flexdashboard)
library(tidyverse)
library(readxl)
library(janitor)
library(sf)
library(plotly)
library(leaflet)
library(classInt)
library(viridisLite)
library(scales)
library(glue)

source("R/utils_read.R"); source("R/utils_wrangle.R"); source("R/theme.R")

# paths
csa_path   <- "data_raw/csa_lga_ye_jun_2025.xlsx"
seifa_path <- "data_raw/abs_seifa_lga_2021.xlsx"
asgs_path  <- "data_raw/LGA_2025_AUST_GDA2020.shp"

csa_raw  <- read_csa_lga(csa_path)
seifa    <- read_seifa_lga(seifa_path)
lga_sf_raw <- {
  ext <- tolower(tools::file_ext(asgs_path))
  if (ext == "gpkg") {
    sf::st_read(asgs_path, layer = "LGA_2021_AUST_GDA2020", quiet = TRUE)
  } else {
    sf::st_read(asgs_path, quiet = TRUE)
  }
} %>%
  janitor::clean_names()

name_col <- intersect(
  c("lga_name_2025", "lga_name25", "lga_name_2021", "lga_name21"),
  names(lga_sf_raw)
)[1]

if (is.na(name_col)) {
  stop("Could not find an LGA name column in ", asgs_path)
}

lga_sf_raw$lga <- str_squish(str_remove(lga_sf_raw[[name_col]], " \\(.*\\)$"))

lga_sf <- lga_sf_raw %>%
  select(lga, geometry)

# make CSA look proper
csa <- csa_raw %>%
  prep_rates() %>%
  focus_offences()

# select years 2018 to 2025
csa_focus <- csa %>%
  filter(year_end >= 2018)

# SEIFA       keep VIC only and derive deciles
seifa_vic <- prep_seifa(seifa)

# join to geometry
map_df <- csa_focus %>%
  group_by(lga, year_end, focus_flag) %>%
  summarise(rate = sum(rate, na.rm = TRUE), .groups = "drop") %>%
  left_join(seifa_vic, by = "lga") %>%
  inner_join(lga_sf, by = "lga") %>%
  sf::st_as_sf()

the_pal <- viridisLite::viridis
```

##


### The Problem

#### Narrative
Theft from motor vehicles and number plates have surged in Victoria since 2018, but not everywhere in the state is affected equally. This visualisation looks at how these thefts evolved over time and what socio-economic factors might explain the rise.

- **Objective**: Show how theft from cars and plates surged in Victoria since 2018, the areas most affected, and socio-economic drivers.
- **Key takeaway**: The surge in thefts is concentrated in a few LGAs with high socio-economic disadvantage.
- **References**:
  - Crime Statistics Agency Victoria, State Government of Victoria. (2025, September 25). *Download data*. https://www.crimestatistics.vic.gov.au/crime-statistics/latest-victorian-crime-data/download-data
  - Digital boundary files. (n.d.). Australian Bureau of Statistics. https://www.abs.gov.au/statistics/standards/australian-statistical-geography-standard-asgs-edition-3/jul2021-jun2026/access-and-downloads/digital-boundary-files#cite-window1
  - Socio-Economic Indexes for Areas (SEIFA), Australia, 2021. (2023, April 27). Australian Bureau of Statistics. https://www.abs.gov.au/statistics/people/people-and-communities/socio-economic-indexes-areas-seifa-australia/latest-release#cite-window1

----------------------------------

```{r time_series, echo=FALSE}
state_ts <- csa_focus %>%
  group_by(year_end, focus_flag) %>%
  summarise(rate = sum(rate, na.rm = TRUE), .groups = "drop")
ggplot(state_ts, aes(year_end, rate, colour = focus_flag)) +
  geom_line(size = 1.1) +
  scale_x_continuous(breaks = 2018:2025) +
  scale_y_continuous(labels = scales::label_number(big.mark = ",")) +
  scale_colour_manual(values = viridisLite::viridis(2)) +
  labs(x = NULL, y = "Rate per 100,000",
       colour = NULL,
       title = "Theft from Motor Vehicles and Number Plates in Victoria",
       subtitle = "2018-2025: Trends over time",
       caption = "Data Source: CSA YE June 2025") +
  theme_pub()
```


### Hot Spots in 2025
```{r choropleth_map, echo=FALSE}
yr <- 2025
map_latest <- map_df %>%
  filter(year_end == yr, focus_flag == "Theft from motor vehicle") %>%
  filter(!is.na(rate))

if (nrow(map_latest) == 0) {
  map_latest <- lga_sf %>%
    mutate(
      focus_flag = "Theft from motor vehicle",
      year_end = yr,
      rate = NA_real_
    )
}

pal <- colorNumeric(viridisLite::viridis(7), map_latest$rate, na.color = "#CCCCCC")

leaflet(map_latest) %>%
  addProviderTiles("CartoDB.Positron") %>%
  addPolygons(
    fillColor = ~pal(rate),
    fillOpacity = 0.85, weight = 0.5, color = "#333",
    label = ~glue("{lga}: {scales::comma(round(rate))} per 100k"),
    highlightOptions = highlightOptions(weight = 2, color = "#000", bringToFront = TRUE)
  ) %>%
  addLegend("bottomright", pal = pal,
            values = ~rate, title = glue("Rate per 100k, {yr}"))

```

### SEIFA vs Crime Rate
```{r}
ctx <- map_df %>%
  filter(year_end == 2025, focus_flag == "Theft from motor vehicle") %>%
  st_drop_geometry() %>%
  mutate(seifa_dec = factor(irsad_decile_vic, levels = 1:10))

p2 <- ggplot(ctx, aes(seifa_dec, rate)) +
  geom_boxplot(outlier.alpha = 0.3) +
  labs(x = "Socio-economic Disadvantage", y = "Rate per 100,000",
       title = "Theft Rates by Socio-economic Disadvantage (SEIFA)",
       subtitle = "2025: Boxplot by SEIFA decile") +
  theme_pub()

plotly::ggplotly(p2)
```