Introduction

Beyond the Landslide

The Real Story of the 2025 Australian Federal Election

This data-driven dashboard explores the 2025 Federal Election using open Australian Electoral Commission (AEC) datasets.
The media labelled the result a “Labor landslide”, but a closer look at the data reveals an uneven performance across states and many seats won by narrow margins.


Key Questions
  • How did first-preference votes vary by party across Victoria?
  • Which divisions were truly marginal, and what does that mean for 2028?




Assignment 3 – Data Visualisation

Student: Sai Nihanth Edara (S4123208)

About the Data

About the Dataset

Two Complementary Election Datasets from the AEC

The visualisations in this storyboard are powered by Australian Electoral Commission (AEC). Two official CSV files are used to explore voting behaviour and seat competitiveness in the 2025 Federal Election.


  • HouseTcpByCandidateByPollingPlaceDownload-31496.csv

    Provides Two-Candidate-Preferred (TCP) results for every polling place and division.
    It contains details such as state, division name, candidate, party, total votes, and final TCP percentages used to identify marginal seats.

  • HouseStateFirstPrefsByPollingPlaceDownload-31496-VIC.csv

    Contains First-Preference votes for each candidate and party in Victoria.
    This reveals initial voter loyalties before preferences were distributed, allowing analysis of party vote share across the state.

Data Cleaning & Processing

Data Cleaning & Processing

Preparing the AEC data for visualisation

Both AEC datasets were cleaned and transformed using R packages tidyverse and janitor to make the results suitable for visual analysis. The goal was to create summary tables showing party vote shares and margins of victory at the division level.


  • Remove metadata rows – Skipped the first line in both CSVs (skip = 1).
  • Standardise column names – Used clean_names() for consistent formatting.
  • Summarise by division & party – Aggregated vote totals using group_by() and summarise().
  • Compute vote shares (%) – Added proportional calculations with mutate().
  • Identify marginal seats – Calculated the difference between the top two TCP candidates per division.


Example transformation (simplified):

# A tibble: 6 × 3
  party_nm                                                    total_votes  share
  <chr>                                                             <dbl>  <dbl>
1 Animal Justice Party                                               4451  0.138
2 Australian Labor Party                                          1043383 32.4  
3 Citizens Party                                                     5673  0.176
4 FUSION | Planet Rescue | Whistleblower Protection | Innova…        3282  0.102
5 Family First                                                      66436  2.07 
6 Gerard Rennick People First                                        4315  0.134

Victoria – First Preferences

Victoria – First Preference Votes by Party

Who did Victorians choose first?

This visualisation shows the share of first-preference votes across political parties in Victoria during the 2025 Federal Election.
It captures voter loyalty before preference redistribution in Australia’s preferential voting system.

Victoria – Marginal Divisions (TCP)

Victoria – Marginal Divisions (TCP)

Where the 2025 election was closest

This chart shows the most competitive Victorian seats based on the Two-Candidate-Preferred (TCP) results in the AEC data.
Seats with the smallest margins are the ones most likely to change hands in the next election.

Interpretation & Insights

Interpretation & Insights

Understanding the story behind the numbers

The 2025 Australian Federal Election is often described as a “Labor landslide.”
Yet, a closer examination of the Victorian results reveals a more complex political landscape.


  • Labor’s strong base: Labor dominated Victoria’s first preferences, particularly in metropolitan areas such as Melbourne and Ballarat.
  • Growing diversity in votes: Greens and Independents continued to strengthen their share, reflecting voter interest in local and environmental issues.
  • Marginal seats remain decisive: Despite Labor’s overall success, many divisions were won by less than 2 %.
    This underlines that even a “landslide” can rest on razor-thin margins in key battlegrounds.
  • Outlook for 2028: These marginal divisions, especially those in outer metropolitan and regional areas will be critical in shaping future campaigns and party strategies.


Take-home message:
While aggregate results tell a story of dominance, local-level data shows that electoral competitiveness and voter diversity remain strong across Victoria. This demonstrates how data storytelling can move beyond headlines to uncover deeper truths in political behaviour.

References

References

Data Sources:

  • Australian Electoral Commission (AEC). (2025). House of Representatives – Two Candidate Preferred by Polling Place (2025 Federal Election).
    Retrieved from results.aec.gov.au
  • Australian Electoral Commission (AEC). (2025). House of Representatives – State First Preferences by Polling Place (Victoria).
    Retrieved from results.aec.gov.au
---
title: "S4123208 Assignment 3"
output:
  flexdashboard::flex_dashboard:
    storyboard: true
    theme: united
    source_code: embed
---


```{r setup, include=FALSE}
library(tidyverse)
library(flexdashboard)
library(readr)
library(stringr)
library(tidyverse)
library(janitor)
knitr::opts_chunk$set(message = FALSE, warning = FALSE)
```

### Introduction
<div style="text-align:center; padding:40px;">

<h2 style="font-weight:800; color:#7B1FA2;">Beyond the Landslide</h2>
<h3 style="margin-top:-10px;">The Real Story of the 2025 Australian Federal Election</h3>

<p style="font-size:17px; max-width:800px; margin:auto;">
This data-driven dashboard explores the 2025 Federal Election using 
<b>open Australian Electoral Commission (AEC)</b> datasets.  
The media labelled the result a “Labor landslide”, but a closer look at the data 
reveals an uneven performance across states and many seats won by 
narrow margins.
</p>

<br>

<div style="text-align:left; display:inline-block; font-size:16px; color:#333;">
<b>Key Questions</b>
<ul>
<li>How did first-preference votes vary by party across Victoria?</li>
<li>Which divisions were truly marginal, and what does that mean for 2028?</li>
</ul>
</div>

<br><br>

<br><b>Assignment 3 – Data Visualisation</b>  
<br><b>Student:</b> Sai Nihanth Edara (S4123208)
</p>

</div>
###  About the Data
<div style="text-align:center; padding:30px;">

<h2 style="font-weight:700; color:#7B1FA2;">About the Dataset</h2>
<h3>Two Complementary Election Datasets from the AEC</h3>

<p style="font-size:17px; max-width:850px; margin:auto;">
The visualisations in this storyboard are powered by <b>Australian Electoral Commission (AEC)</b></a>.
Two official CSV files are used to explore voting behaviour and seat competitiveness in the
<b>2025 Federal Election</b>.
</p>

<br>

<div style="text-align:left; display:inline-block; font-size:16px; margin-top:10px;">
<ul>
<li><b>HouseTcpByCandidateByPollingPlaceDownload-31496.csv</b><br><br>
Provides <b>Two-Candidate-Preferred (TCP)</b> results for every polling place and division.<br>
It contains details such as state, division name, candidate, party, total votes,
and final TCP percentages used to identify <b>marginal seats</b>.</li><br>

<li><b>HouseStateFirstPrefsByPollingPlaceDownload-31496-VIC.csv</b><br><br>
Contains <b>First-Preference votes</b> for each candidate and party in Victoria.<br>
This reveals initial voter loyalties before preferences were distributed, allowing analysis of
<b>party vote share</b> across the state.</li>
</ul>
</div>

```{r}
tcp <- readr::read_csv("HouseTcpByCandidateByPollingPlaceDownload-31496.csv",
                       skip = 1) |>
  clean_names()
prefs_vic <- readr::read_csv("HouseStateFirstPrefsByPollingPlaceDownload-31496-VIC.csv",
                             skip = 1) |>
  clean_names()
```

### Data Cleaning & Processing
<div style="text-align:center; padding:30px;">

<h2 style="font-weight:700; color:#7B1FA2;">Data Cleaning & Processing</h2>
<h3>Preparing the AEC data for visualisation</h3>

<p style="font-size:17px; max-width:850px; margin:auto;">
Both AEC datasets were cleaned and transformed using <b>R</b> packages 
<code>tidyverse</code> and <code>janitor</code> to make the results suitable for visual analysis.
The goal was to create summary tables showing <b>party vote shares</b> and 
<b>margins of victory</b> at the division level.
</p>

<br>

<div style="text-align:left; display:inline-block; font-size:16px;">
<ul>
<li><b>Remove metadata rows</b> – Skipped the first line in both CSVs (<code>skip = 1</code>).</li>
<li><b>Standardise column names</b> – Used <code>clean_names()</code> for consistent formatting.</li>
<li><b>Summarise by division & party</b> – Aggregated vote totals using <code>group_by()</code> and <code>summarise()</code>.</li>
<li><b>Compute vote shares (%)</b> – Added proportional calculations with <code>mutate()</code>.</li>
<li><b>Identify marginal seats</b> – Calculated the difference between the top two TCP candidates per division.</li>
</ul>
</div>

<br>

<p style="font-size:16px;">Example transformation (simplified):</p>

```{r}
library(dplyr)

# Summarise first preferences in Victoria
vic_summary_party <- prefs_vic %>%
  group_by(party_nm) %>%
  summarise(total_votes = sum(ordinary_votes, na.rm = TRUE)) %>%
  mutate(share = 100 * total_votes / sum(total_votes))
head(vic_summary_party)

```

### Victoria – First Preferences

<div style="text-align:center; padding:30px;">

<h2 style="font-weight:800; color:#7B1FA2; margin-bottom:5px;">Victoria – First Preference Votes by Party</h2>
<h3>Who did Victorians choose first?</h3>

<p style="font-size:17px; max-width:800px; margin:auto;">
This visualisation shows the share of <b>first-preference votes</b> across political parties in Victoria during the 
<b>2025 Federal Election</b>.  
It captures voter loyalty before preference redistribution in Australia’s preferential voting system.
</p>

```{r, fig.width=9, fig.height=5}
vic_summary_party <- prefs_vic %>%
  group_by(party_nm) %>%
  summarise(total_votes = sum(ordinary_votes, na.rm = TRUE), .groups = "drop") %>%
  mutate(share = 100 * total_votes / sum(total_votes)) %>%
  arrange(desc(share))

ggplot(vic_summary_party, aes(x = reorder(party_nm, share), y = share)) +
  geom_col(fill = "#E53935") +
  coord_flip() +
  geom_text(aes(label = sprintf("%.1f%%", share)), hjust = -0.2, size = 4) +
  labs(
    title = "First Preference by Party in Victoria, 2025",
    subtitle = "Labor leads Victoria’s first preferences",
    x = NULL, y = "Vote Share (%)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", color = "#333"),
    plot.subtitle = element_text(size = 11, color = "#555"),
    axis.text.y = element_text(size = 11),
    axis.text.x = element_text(size = 10)
  ) +
  ylim(0, max(vic_summary_party$share) + 5)
```

### Victoria – Marginal Divisions (TCP)

<div style="text-align:center; padding:30px;">

<h2 style="font-weight:800; color:#7B1FA2; margin-bottom:5px;">Victoria – Marginal Divisions (TCP)</h2>
<h3 margin-top:0;">Where the 2025 election was closest</h3>

<p style="font-size:17px; max-width:800px; margin:auto;">
This chart shows the <b>most competitive Victorian seats</b> based on the
<b>Two-Candidate-Preferred (TCP)</b> results in the AEC data.  
Seats with the smallest margins are the ones most likely to change hands in the next election.
</p>


```{r, fig.width=9, fig.height=5}
# 1.aggregate TCP votes per division+party, but only for VIC
tcp_vic <- tcp %>%
  filter(state_ab == "VIC") %>% 
  group_by(division_nm, party_nm) %>%
  summarise(total_votes = sum(ordinary_votes, na.rm = TRUE), .groups = "drop")

# 2. for each division, sort parties by votes and keep top 2
tcp_vic_top2 <- tcp_vic %>%
  group_by(division_nm) %>%
  arrange(desc(total_votes), .by_group = TRUE) %>%
  slice_head(n = 2) %>%       
  ungroup()

# 3. turn those 2 rows into wide form so we can compute margin safely
tcp_vic_wide <- tcp_vic_top2 %>%
  group_by(division_nm) %>%
  mutate(div_total = sum(total_votes, na.rm = TRUE)) %>%
  mutate(share = 100 * total_votes / div_total) %>%
  arrange(desc(share), .by_group = TRUE) %>%
  # now we have exactly 2 rows per division (if there were 2 candidates)
  summarise(
    top_share = first(share),
    second_share = nth(share, 2),
    .groups = "drop"
  ) %>%
  # keep only divisions that actually had 2 candidates
  filter(!is.na(second_share)) %>%
  mutate(margin = top_share - second_share)

# 4. pick the 10 smallest positive margins
marginals_vic <- tcp_vic_wide %>%
  arrange(margin) %>%
  slice_head(n = 10)

ggplot(marginals_vic, aes(x = reorder(division_nm, margin), y = margin)) +
  geom_col(fill = "#1E88E5") +
  coord_flip() +
  geom_text(aes(label = sprintf("%.1f%%", margin)), hjust = -0.1, size = 4) +
  labs(
    title = "Most Marginal Divisions in Victoria (2025)",
    subtitle = "Ten Victorian divisions with the smallest TCP winning margins.",
    x = NULL,
    y = "TCP margin (percentage points)"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", color = "#333"),
    plot.subtitle = element_text(size = 11, color = "#555"),
    axis.text.y = element_text(size = 11)
  ) +
  ylim(0, max(marginals_vic$margin) + 2)
```

### Interpretation & Insights
<div style="text-align:center; padding:30px;">

<h2 style="font-weight:800; color:#7B1FA2;">Interpretation & Insights</h2>
<h3 margin-top:0;">Understanding the story behind the numbers</h3>


<p style="font-size:17px; max-width:850px; margin:auto;">
The 2025 Australian Federal Election is often described as a <i>“Labor landslide.”</i>  
Yet, a closer examination of the <b>Victorian results</b> reveals a more complex political landscape.
</p>

<br>

<div style="text-align:left; display:inline-block; font-size:16px; max-width:900px;">
<ul>
<li><b> Labor’s strong base:</b> Labor dominated Victoria’s first preferences, particularly in metropolitan areas such as Melbourne and Ballarat.</li>

<li><b> Growing diversity in votes:</b> Greens and Independents continued to strengthen their share, reflecting voter interest in local and environmental issues.</li>

<li><b> Marginal seats remain decisive:</b> Despite Labor’s overall success, many divisions were won by <b>less than 2 %</b>.  
This underlines that even a “landslide” can rest on razor-thin margins in key battlegrounds.</li>

<li><b> Outlook for 2028:</b> These marginal divisions, especially those in outer metropolitan and regional areas will be critical in shaping future campaigns and party strategies.</li>
</ul>
</div>

<br>

<p style="font-size:16px; max-width:850px; margin:auto;">
<b>Take-home message:</b>  
While aggregate results tell a story of dominance, local-level data shows that electoral competitiveness and voter diversity remain strong across Victoria. This demonstrates how <b>data storytelling</b> can move beyond headlines to uncover deeper truths in political behaviour.
</p>

</div>


### References
<div style="text-align:center; padding:30px;">

<h2 style="font-weight:800; color:#7B1FA2;">References</h2>

<div style="text-align:left; max-width:850px; font-size:16px; line-height:1.6;">

<p><b>Data Sources:</b></p>

<ul>
<li>Australian Electoral Commission (AEC). (2025). <em>House of Representatives – Two Candidate Preferred by Polling Place (2025 Federal Election)</em>.  
Retrieved from <a href="https://results.aec.gov.au/31496/Website/HouseDownloadsMenu-31496-Csv.htm">results.aec.gov.au</a></li>

<li>Australian Electoral Commission (AEC). (2025). <em>House of Representatives – State First Preferences by Polling Place (Victoria)</em>.  
Retrieved from <a href="https://results.aec.gov.au/31496/Website/HouseDownloadsMenu-31496-Csv.htm">results.aec.gov.au</a></li>
</ul>