Understanding Australia’s Inflation
The cost of everyday items can change quite a lot over time. Groceries, electricity, rent and transport do not always become more expensive at the same rate. Looking at Australia’s Consumer Price Index (CPI) data helps us understand these differences and see how prices have changed.
In this report, I explore Australian CPI data using five interactive visualisations. Each chart looks at the data from a different angle, including increases and decreases in prices, changes over time, and differences between CPI measures. Together, the charts help identify the main patterns in the data and give a clearer picture of how inflation varies across different areas.
# Install missing packages in the RStudio Console if needed:
# install.packages(c("readr", "dplyr", "ggplot2", "plotly", "knitr"))
library(readr)
library(dplyr)
library(ggplot2)
library(plotly)
library(knitr)
knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE,
fig.width = 10,
fig.height = 6
)
Save australia_cpi_data.csv in the same folder as this R
Markdown file before knitting.
# Load the package
library(readr)
# Import the Australian CPI dataset
cpi_raw <- read_csv(
"/Users/prajwalmalipatil8/Downloads/Price Index/australia_cpi_data.csv",
show_col_types = FALSE
)
# Check the dimensions of the imported data
data.frame(
rows = nrow(cpi_raw),
columns = ncol(cpi_raw)
)
# Show the column names
names(cpi_raw)
## [1] "STRUCTURE" "STRUCTURE_ID" "STRUCTURE_NAME"
## [4] "ACTION" "MEASURE" "Measure"
## [7] "INDEX" "Index" "TSEST"
## [10] "Adjustment Type" "REGION" "Region"
## [13] "FREQ" "Frequency" "TIME_PERIOD"
## [16] "Time Period" "OBS_VALUE" "Observation Value"
## [19] "UNIT_MEASURE" "Unit of Measure" "OBS_STATUS"
## [22] "Observation Status" "DECIMALS" "Decimals"
## [25] "OBS_COMMENT" "Observation Comment" "BASE_PERIOD"
## [28] "Reference Base Period"
# Preview the first few records
head(cpi_raw, 10)
# Check the structure and data types
str(cpi_raw)
## spc_tbl_ [644 × 28] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
## $ STRUCTURE : chr [1:644] "DATAFLOW" "DATAFLOW" "DATAFLOW" "DATAFLOW" ...
## $ STRUCTURE_ID : chr [1:644] "ABS:CPI(2.0.0)" "ABS:CPI(2.0.0)" "ABS:CPI(2.0.0)" "ABS:CPI(2.0.0)" ...
## $ STRUCTURE_NAME : chr [1:644] "Consumer Price Index (CPI)" "Consumer Price Index (CPI)" "Consumer Price Index (CPI)" "Consumer Price Index (CPI)" ...
## $ ACTION : chr [1:644] "I" "I" "I" "I" ...
## $ MEASURE : num [1:644] 3 3 3 3 3 3 3 3 3 3 ...
## $ Measure : chr [1:644] "Percentage change from previous year" "Percentage change from previous year" "Percentage change from previous year" "Percentage change from previous year" ...
## $ INDEX : num [1:644] 40077 40077 40077 40077 131187 ...
## $ Index : chr [1:644] "Postal services" "Postal services" "Postal services" "Postal services" ...
## $ TSEST : num [1:644] 10 10 10 10 10 10 10 10 10 10 ...
## $ Adjustment Type : chr [1:644] "Original" "Original" "Original" "Original" ...
## $ REGION : num [1:644] 50 50 50 50 50 50 50 50 50 50 ...
## $ Region : chr [1:644] "Australia" "Australia" "Australia" "Australia" ...
## $ FREQ : chr [1:644] "M" "M" "M" "M" ...
## $ Frequency : chr [1:644] "Monthly" "Monthly" "Monthly" "Monthly" ...
## $ TIME_PERIOD : chr [1:644] "2026-05" "2026-06" "2026-07" "2026-08" ...
## $ Time Period : logi [1:644] NA NA NA NA NA NA ...
## $ OBS_VALUE : num [1:644] 11.6 8.7 6.8 7.5 4.7 4.9 4.7 4.6 -1.9 -1.8 ...
## $ Observation Value : logi [1:644] NA NA NA NA NA NA ...
## $ UNIT_MEASURE : chr [1:644] "PCT" "PCT" "PCT" "PCT" ...
## $ Unit of Measure : chr [1:644] "Percent" "Percent" "Percent" "Percent" ...
## $ OBS_STATUS : chr [1:644] NA NA NA NA ...
## $ Observation Status : chr [1:644] NA NA NA NA ...
## $ DECIMALS : logi [1:644] NA NA NA NA NA NA ...
## $ Decimals : logi [1:644] NA NA NA NA NA NA ...
## $ OBS_COMMENT : logi [1:644] NA NA NA NA NA NA ...
## $ Observation Comment : logi [1:644] NA NA NA NA NA NA ...
## $ BASE_PERIOD : num [1:644] 25 25 25 25 25 25 25 25 25 25 ...
## $ Reference Base Period: chr [1:644] "Sep 2025 = 100.0" "Sep 2025 = 100.0" "Sep 2025 = 100.0" "Sep 2025 = 100.0" ...
## - attr(*, "spec")=
## .. cols(
## .. STRUCTURE = col_character(),
## .. STRUCTURE_ID = col_character(),
## .. STRUCTURE_NAME = col_character(),
## .. ACTION = col_character(),
## .. MEASURE = col_double(),
## .. Measure = col_character(),
## .. INDEX = col_double(),
## .. Index = col_character(),
## .. TSEST = col_double(),
## .. `Adjustment Type` = col_character(),
## .. REGION = col_double(),
## .. Region = col_character(),
## .. FREQ = col_character(),
## .. Frequency = col_character(),
## .. TIME_PERIOD = col_character(),
## .. `Time Period` = col_logical(),
## .. OBS_VALUE = col_double(),
## .. `Observation Value` = col_logical(),
## .. UNIT_MEASURE = col_character(),
## .. `Unit of Measure` = col_character(),
## .. OBS_STATUS = col_character(),
## .. `Observation Status` = col_character(),
## .. DECIMALS = col_logical(),
## .. Decimals = col_logical(),
## .. OBS_COMMENT = col_logical(),
## .. `Observation Comment` = col_logical(),
## .. BASE_PERIOD = col_double(),
## .. `Reference Base Period` = col_character()
## .. )
## - attr(*, "problems")=<externalptr>
# What measure, region and frequency are represented?
cpi_raw %>%
count(Measure, Region, Frequency, sort = TRUE) %>%
kable(caption = "Measures, regions and reporting frequency")
| Measure | Region | Frequency | n |
|---|---|---|---|
| Percentage change from previous year | Australia | Monthly | 644 |
# Count records by reporting month
cpi_raw %>%
count(TIME_PERIOD, name = "records") %>%
arrange(TIME_PERIOD) %>%
kable(caption = "Records available for each reporting month")
| TIME_PERIOD | records |
|---|---|
| 2026-05 | 161 |
| 2026-06 | 161 |
| 2026-07 | 161 |
| 2026-08 | 161 |
The file contains machine-readable fields (for example,
TIME_PERIOD and OBS_VALUE) alongside
descriptive versions of some fields. The analysis below uses the
machine-readable fields and retains the series identifier, adjustment
type and observation status for validation.
cpi_clean <- cpi_raw %>%
transmute(
series_id = INDEX,
category = Index,
measure = Measure,
region = Region,
frequency = Frequency,
time_period = TIME_PERIOD,
date = as.Date(paste0(TIME_PERIOD, "-01")),
value = OBS_VALUE,
unit = `Unit of Measure`,
adjustment_type = `Adjustment Type`,
observation_status = OBS_STATUS,
reference_base = `Reference Base Period`
) %>%
arrange(series_id, date)
# Preview the analysis-ready data
head(cpi_clean, 10)
# Summary of the cleaned data
data_summary <- cpi_clean %>%
summarise(
rows = n(),
unique_series = n_distinct(series_id),
unique_category_labels = n_distinct(category),
missing_values = sum(is.na(value)),
first_period = min(date, na.rm = TRUE),
last_period = max(date, na.rm = TRUE)
)
kable(data_summary, caption = "Summary of the cleaned dataset")
| rows | unique_series | unique_category_labels | missing_values | first_period | last_period |
|---|---|---|---|---|---|
| 644 | 161 | 153 | 0 | 2026-05-01 | 2026-08-01 |
# Count missing values in each analysis column
missing_summary <- data.frame(
column = names(cpi_clean),
missing_count = vapply(cpi_clean, function(x) sum(is.na(x)), integer(1))
)
kable(missing_summary, caption = "Missing values by column")
| column | missing_count | |
|---|---|---|
| series_id | series_id | 0 |
| category | category | 0 |
| measure | measure | 0 |
| region | region | 0 |
| frequency | frequency | 0 |
| time_period | time_period | 0 |
| date | date | 0 |
| value | value | 0 |
| unit | unit | 0 |
| adjustment_type | adjustment_type | 0 |
| observation_status | observation_status | 643 |
| reference_base | reference_base | 0 |
# Check whether any series has more than one record for the same month
duplicate_check <- cpi_clean %>%
count(series_id, date, name = "records") %>%
filter(records > 1)
if (nrow(duplicate_check) == 0) {
cat("No duplicate series-and-month combinations were found.")
} else {
kable(duplicate_check, caption = "Duplicate series-and-month combinations")
}
## No duplicate series-and-month combinations were found.
Different series can share the same category label. For that reason,
the analysis keeps series_id as well as the category name
instead of combining records by category label alone.
cpi_clean %>%
count(adjustment_type, sort = TRUE) %>%
kable(caption = "Records by adjustment type")
| adjustment_type | n |
|---|---|
| Original | 632 |
| Seasonally Adjusted | 12 |
For the charts below, we use the original series to keep the comparison consistent. This filter is explicit so it can be changed if a different adjustment type is required.
cpi_original <- cpi_clean %>%
filter(adjustment_type == "Original", !is.na(value), !is.na(date))
# Check the number of records after filtering
data.frame(
rows = nrow(cpi_original),
series = n_distinct(cpi_original$series_id),
first_period = min(cpi_original$date, na.rm = TRUE),
last_period = max(cpi_original$date, na.rm = TRUE)
)
The values in this file represent percentage change from the previous year, not CPI index numbers. Positive values indicate an increase compared with the same period a year earlier; negative values indicate a decrease.
latest_date <- max(cpi_original$date, na.rm = TRUE)
latest_changes <- cpi_original %>%
filter(date == latest_date) %>%
group_by(series_id, category) %>%
summarise(value = mean(value, na.rm = TRUE), .groups = "drop") %>%
filter(is.finite(value)) %>%
arrange(desc(abs(value))) %>%
slice_head(n = 20) %>%
mutate(
direction = ifelse(value >= 0, "Increase", "Decrease"),
series_label = paste0(category, " (", series_id, ")"),
series_label = reorder(series_label, value)
)
p_diverging <- ggplot(
latest_changes,
aes(
x = value,
y = series_label,
fill = direction,
text = paste0(
"Category: ", category,
"<br>Series ID: ", series_id,
"<br>Annual change: ", round(value, 2), "%"
)
)
) +
geom_col(width = 0.7) +
geom_vline(xintercept = 0, colour = "black", linewidth = 0.5) +
scale_fill_manual(
values = c("Increase" = "#2878B5", "Decrease" = "#D95F59")
) +
labs(
title = "Which CPI categories increased or decreased the most?",
subtitle = paste("Latest available period:", format(latest_date, "%B %Y")),
x = "Percentage change from previous year (%)",
y = NULL,
fill = "Direction"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
legend.position = "bottom"
)
ggplotly(p_diverging, tooltip = "text") %>%
layout(margin = list(l = 180, r = 30, t = 100, b = 70))
number_of_months <- n_distinct(cpi_original$date)
complete_series <- cpi_original %>%
group_by(series_id, category) %>%
summarise(
months_available = n_distinct(date[!is.na(value)]),
.groups = "drop"
) %>%
filter(months_available == number_of_months) %>%
arrange(category, series_id) %>%
slice_head(n = 8)
trend_data <- cpi_original %>%
semi_join(complete_series, by = c("series_id", "category")) %>%
mutate(
series_label = paste0(category, " (", series_id, ")")
) %>%
arrange(date)
p_trends <- ggplot(
trend_data,
aes(
x = date,
y = value,
colour = series_label,
group = series_label,
text = paste0(
"Category: ", category,
"<br>Date: ", format(date, "%B %Y"),
"<br>Annual change: ", round(value, 2), "%"
)
)
) +
geom_line(linewidth = 0.8) +
geom_point(size = 2) +
scale_x_date(date_labels = "%b %Y", date_breaks = "1 month") +
labs(
title = "How have annual CPI changes moved over time?",
x = "Month",
y = "Percentage change from previous year (%)",
colour = "CPI category"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom",
legend.text = element_text(size = 9)
)
ggplotly(p_trends, tooltip = "text") %>%
layout(
margin = list(l = 70, r = 30, t = 100, b = 190),
legend = list(
orientation = "h",
x = 0.5,
xanchor = "center",
y = -0.4,
yanchor = "top",
font = list(size = 9)
)
)
heatmap_series <- cpi_original %>%
group_by(series_id, category) %>%
summarise(
variation = if (sum(!is.na(value)) >= 2) {
max(value, na.rm = TRUE) - min(value, na.rm = TRUE)
} else {
NA_real_
},
.groups = "drop"
) %>%
filter(is.finite(variation)) %>%
arrange(desc(variation)) %>%
slice_head(n = 15)
heatmap_data <- cpi_original %>%
semi_join(heatmap_series, by = c("series_id", "category")) %>%
mutate(
series_label = paste0(category, " (", series_id, ")"),
month_label = format(date, "%b %Y")
) %>%
group_by(series_id, category, series_label, date, month_label) %>%
summarise(value = mean(value, na.rm = TRUE), .groups = "drop")
heatmap_data$series_label <- factor(
heatmap_data$series_label,
levels = rev(unique(heatmap_data$series_label))
)
p_heatmap <- ggplot(
heatmap_data,
aes(
x = date,
y = series_label,
fill = value,
text = paste0(
"Category: ", category,
"<br>Month: ", month_label,
"<br>Annual change: ", round(value, 2), "%"
)
)
) +
geom_tile(colour = "white", linewidth = 0.2) +
scale_x_date(date_labels = "%b %Y", date_breaks = "1 month") +
scale_fill_gradient2(
low = "#D95F59",
mid = "#F7F7F7",
high = "#2878B5",
midpoint = 0,
name = "Annual change (%)"
) +
labs(
title = "How do annual CPI changes differ across categories and months?",
x = "Month",
y = "CPI category"
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1)
)
ggplotly(p_heatmap, tooltip = "text") %>%
layout(margin = list(l = 200, r = 60, t = 100, b = 80))
first_date <- min(cpi_original$date, na.rm = TRUE)
last_date <- max(cpi_original$date, na.rm = TRUE)
comparison_data <- cpi_original %>%
filter(date %in% c(first_date, last_date)) %>%
group_by(series_id, category, date) %>%
summarise(value = mean(value, na.rm = TRUE), .groups = "drop") %>%
mutate(
period = ifelse(date == first_date, "First month", "Latest month")
) %>%
select(series_id, category, period, value) %>%
tidyr::pivot_wider(names_from = period, values_from = value) %>%
filter(
is.finite(`First month`),
is.finite(`Latest month`)
) %>%
mutate(
difference = `Latest month` - `First month`,
series_label = paste0(category, " (", series_id, ")")
) %>%
arrange(desc(abs(difference))) %>%
slice_head(n = 15) %>%
mutate(
series_label = reorder(series_label, difference)
)
dumbbell_data <- comparison_data %>%
tidyr::pivot_longer(
cols = c(`First month`, `Latest month`),
names_to = "period",
values_to = "value"
)
p_dumbbell <- ggplot(
comparison_data,
aes(
y = series_label,
x = `First month`,
xend = `Latest month`,
text = paste0(
"Category: ", category,
"<br>First month: ", round(`First month`, 2), "%",
"<br>Latest month: ", round(`Latest month`, 2), "%",
"<br>Difference: ", round(difference, 2), " percentage points"
)
)
) +
geom_segment(
aes(
yend = series_label,
x = `First month`,
xend = `Latest month`
),
colour = "grey65",
linewidth = 1
) +
geom_point(
aes(x = `First month`),
colour = "#D95F59",
size = 2.8
) +
geom_point(
aes(x = `Latest month`),
colour = "#2878B5",
size = 2.8
) +
labs(
title = "How did annual CPI changes differ between the first and latest months?",
subtitle = paste(
format(first_date, "%B %Y"),
"compared with",
format(last_date, "%B %Y")
),
x = "Percentage change from previous year (%)",
y = NULL
) +
theme_minimal(base_size = 11) +
theme(
plot.title = element_text(face = "bold")
)
ggplotly(p_dumbbell, tooltip = "text") %>%
layout(margin = list(l = 190, r = 30, t = 100, b = 70))
latest_date <- max(cpi_original$date, na.rm = TRUE)
# Check the actual category names in your dataset.
available_categories <- sort(unique(cpi_original$category))
print(available_categories)
## [1] "Accessories"
## [2] "Accessories and clothing services"
## [3] "Alcohol and tobacco"
## [4] "Alcoholic beverages"
## [5] "All groups CPI"
## [6] "All groups CPI excluding 'volatile items'"
## [7] "All groups CPI excluding 'volatile items' and holiday travel"
## [8] "All groups CPI excluding Alcohol and tobacco"
## [9] "All groups CPI excluding Clothing and footwear"
## [10] "All groups CPI excluding Communication"
## [11] "All groups CPI excluding Education"
## [12] "All groups CPI excluding food and energy"
## [13] "All groups CPI excluding Food and non-alcoholic beverages"
## [14] "All groups CPI excluding Furnishings, household equipment and services"
## [15] "All groups CPI excluding Health"
## [16] "All groups CPI excluding Housing"
## [17] "All groups CPI excluding Housing and Insurance and financial services"
## [18] "All groups CPI excluding Insurance and financial services"
## [19] "All groups CPI excluding Medical and hospital services"
## [20] "All groups CPI excluding Recreation and culture"
## [21] "All groups CPI excluding Transport"
## [22] "All groups, goods component"
## [23] "All groups, services component"
## [24] "Audio, visual and computing equipment"
## [25] "Audio, visual and computing equipment and services"
## [26] "Audio, visual and computing media and services"
## [27] "Automotive fuel"
## [28] "Beef and veal"
## [29] "Beer"
## [30] "Books"
## [31] "Bread"
## [32] "Bread and cereal products"
## [33] "Breakfast cereals"
## [34] "Cakes and biscuits"
## [35] "Carpets and other floor coverings"
## [36] "Cheese"
## [37] "Child care"
## [38] "Cleaning and maintenance products"
## [39] "Cleaning, repair and hire of clothing and footwear"
## [40] "Clothing and footwear"
## [41] "Coffee, tea and cocoa"
## [42] "Communication"
## [43] "Dairy and related products"
## [44] "Dental services"
## [45] "Deposit and loan facilities (direct charges)"
## [46] "Discretionary"
## [47] "Discretionary excluding tobacco"
## [48] "Domestic and household services"
## [49] "Domestic holiday travel and accommodation"
## [50] "Education"
## [51] "Eggs"
## [52] "Electricity"
## [53] "Equipment for sports, camping and open-air recreation"
## [54] "Financial services"
## [55] "Fish and other seafood"
## [56] "Food additives and condiments"
## [57] "Food and non-alcoholic beverages"
## [58] "Food products n.e.c."
## [59] "Footwear"
## [60] "Footwear for infants and children"
## [61] "Footwear for men"
## [62] "Footwear for women"
## [63] "Fruit"
## [64] "Fruit and vegetables"
## [65] "Furnishings, household equipment and services"
## [66] "Furniture"
## [67] "Furniture and furnishings"
## [68] "Games, toys and hobbies"
## [69] "Garments"
## [70] "Garments for infants and children"
## [71] "Garments for men"
## [72] "Garments for women"
## [73] "Gas and other household fuels"
## [74] "Glassware, tableware and household utensils"
## [75] "Hairdressing and personal grooming services"
## [76] "Health"
## [77] "Holiday travel and accommodation"
## [78] "Household appliances, utensils and tools"
## [79] "Household textiles"
## [80] "Housing"
## [81] "Ice cream and other dairy products"
## [82] "Insurance"
## [83] "Insurance and financial services"
## [84] "International holiday travel and accommodation"
## [85] "Jams, honey and spreads"
## [86] "Lamb and goat"
## [87] "Maintenance and repair of motor vehicles"
## [88] "Maintenance and repair of the dwelling"
## [89] "Major household appliances"
## [90] "Market goods and services excluding 'volatile items' - Goods"
## [91] "Market goods and services excluding 'volatile items' - Services"
## [92] "Market goods and services excluding 'volatile items' - Total"
## [93] "Meals out and take away foods"
## [94] "Meat and seafoods"
## [95] "Medical and hospital services"
## [96] "Medical products, appliances and equipment"
## [97] "Medical, dental and hospital services"
## [98] "Milk"
## [99] "Motor vehicles"
## [100] "New dwelling purchase by owner-occupiers"
## [101] "Newspapers, books and stationery"
## [102] "Newspapers, magazines and stationery"
## [103] "Non-alcoholic beverages"
## [104] "Non-Discretionary"
## [105] "Non-durable household products"
## [106] "Non-tradables"
## [107] "Oils and fats"
## [108] "Other cereal products"
## [109] "Other financial services"
## [110] "Other food products n.e.c."
## [111] "Other household services"
## [112] "Other housing"
## [113] "Other meats"
## [114] "Other non-durable household products"
## [115] "Other recreation, sport and culture"
## [116] "Other recreational, sporting and cultural services"
## [117] "Other services in respect of motor vehicles"
## [118] "Personal care products"
## [119] "Pets and related products"
## [120] "Pharmaceutical products"
## [121] "Pork"
## [122] "Postal services"
## [123] "Poultry"
## [124] "Preschool and primary education"
## [125] "Private motoring"
## [126] "Property rates and charges"
## [127] "Recreation and culture"
## [128] "Rents"
## [129] "Restaurant meals"
## [130] "Secondary education"
## [131] "Small electric household appliances"
## [132] "Snacks and confectionery"
## [133] "Spare parts and accessories for motor vehicles"
## [134] "Spirits"
## [135] "Sports participation"
## [136] "Take away and fast foods"
## [137] "Telecommunication equipment and services"
## [138] "Tertiary education"
## [139] "Therapeutic appliances and equipment"
## [140] "Tobacco"
## [141] "Tools and equipment for house and garden"
## [142] "Tradables"
## [143] "Transport"
## [144] "Urban transport fares"
## [145] "Utilities"
## [146] "Vegetables"
## [147] "Veterinary and other services for pets"
## [148] "Water and sewerage"
## [149] "Waters, soft drinks and juices"
## [150] "Wine"
# Match these phrases against the category labels in the CSV.
category_patterns <- c(
"All groups",
"Food and non-alcoholic beverages",
"Housing",
"Electricity",
"Automotive fuel",
"Rents"
)
selected_categories <- cpi_original %>%
filter(date == latest_date) %>%
filter(
vapply(
category,
function(x) {
any(grepl(category_patterns, x, ignore.case = TRUE))
},
logical(1)
)
) %>%
group_by(series_id, category) %>%
summarise(value = mean(value, na.rm = TRUE), .groups = "drop") %>%
filter(is.finite(value)) %>%
mutate(
series_label = paste0(category, " (", series_id, ")"),
series_label = reorder(series_label, value)
)
if (nrow(selected_categories) == 0) {
stop(
"No selected category names matched. Check available_categories above ",
"and update category_patterns to match your CSV."
)
}
p_categories <- ggplot(
selected_categories,
aes(
x = value,
y = series_label,
text = paste0(
"Category: ", category,
"<br>Series ID: ", series_id,
"<br>Annual change: ", round(value, 2), "%"
)
)
) +
geom_col(fill = "#2878B5", width = 0.7) +
geom_vline(xintercept = 0, colour = "black", linewidth = 0.4) +
labs(
title = "How do selected CPI categories compare?",
subtitle = paste("Latest available period:", format(latest_date, "%B %Y")),
x = "Percentage change from previous year (%)",
y = NULL
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold")
)
ggplotly(p_categories, tooltip = "text") %>%
layout(margin = list(l = 200, r = 30, t = 100, b = 70))
Visualisation 1: Comparing increases and decreases
This chart compares the CPI measures with the largest positive and negative annual changes. It helps show that price movements are not the same across every measure. The largest increase was in [insert measure and value], while [insert measure and value] recorded the largest decrease. This comparison makes it easier to see which areas experienced the biggest changes.
Visualisation 2: Changes over time
This line chart shows how annual percentage changes moved across selected CPI measures during the available period. Some lines may follow similar patterns, while others move differently. This helps identify whether the selected measures experienced similar changes or followed different trends.
Visualisation 3: Patterns across categories and months
The heatmap provides a quick way to compare CPI changes across several measures and months. Different colours represent different percentage changes, making patterns easier to spot. It also helps highlight measures whose annual changes varied more during the period.
Visualisation 4: Comparing two periods
This chart compares the annual percentage changes in the first and latest months available in the dataset. The distance between the two points shows how much each measure changed between those periods. Measures with larger differences experienced greater movement, while measures with smaller differences remained relatively stable.
Visualisation 5: Comparing selected CPI measures
This chart compares selected CPI measures for the latest available month. It helps show how the reported annual changes differ between the measures included. Because some measures exclude particular items from the overall CPI, the results need to be interpreted carefully rather than treated as completely separate categories.# 6. Interpretation and limitations
The supplied CSV contains monthly observations for the measure “Percentage change from previous year” and the region Australia. The date coverage is determined from the imported file and is reported in the data-quality section above.
The supplied file appears to cover only a short recent period. Therefore, these charts can compare the available series and months, but they should not be used to make claims about long-term inflation trends. A longer historical download would be needed for a robust long-term analysis.
The data also includes multiple series IDs that can share a category label. The series ID is retained in the charts to prevent different series from being silently combined. The selected series and the reasons for selecting them should be reviewed before using these figures in a final narrative.
After exploring the CPI data through five visualisations, it becomes clear that annual price changes can differ across measures and over time. The charts provide different ways to examine these movements, from identifying the largest increases and decreases to comparing patterns between months.
One important point is that the overall CPI figure does not tell the whole story. Looking at individual categories and alternative CPI measures provides more detail, although overlapping measures need to be interpreted carefully. Overall, the visualisations help explain the main patterns in the available data and show why it is useful to examine inflation from more than one perspective.
Data source: Australian Bureau of Statistics (ABS),
Consumer Price Index (CPI). The file analysed here was supplied
as australia_cpi_data.csv. Before submission, add the exact
ABS download page URL and the download date, and verify the title and
release details against the original source.
Acknowledgements:
I acknowledge the Australian Bureau of Statistics (ABS) as the source of the Consumer Price Index data used in this report. I used R and its visualisation packages to clean, analyse and present the data through interactive charts.
Australian Bureau of Statistics. (2026). Consumer Price Index, Australia. https://www.abs.gov.au/statistics/economy/price-indexes-and-inflation/consumer-price-index-australia/latest-release