Module 04 — Bar and Stacked Bar: Labour Force by State
What We’re Building
The Labour Force dataset gives us monthly employment figures across 8 Australian states from 2012–2024 — 1,248 records covering employed persons, unemployed persons, participation rate, and unemployment rate. It is richer than the GDP data and has a monthly cadence that requires bucketing before charting.
By the end of this module you will have:
- A service that buckets monthly data into annual averages
- A grouped bar chart showing employment by state with ECharts’ native toolbox
- A horizontal bar chart showing the latest year’s employment snapshot
- An unemployment rate line chart demonstrating that one service can feed multiple chart types
4.1 — The Data Problem: Monthly Granularity
The labour_force_readings table has 1,248 records — one per state per month.
Charting all 156 months per state produces an illegible chart. We need to bucket
monthly data into annual averages before passing it to ECharts.
The naive approach
|
|
This works but has edge cases — partial years at the start or end of the date range produce lower averages because fewer months contribute to the sum. Writing robust time-series bucketing by hand is tedious.
Introducing groupdate
groupdate solves time-series bucketing cleanly. Add it to the Gemfile:
|
|
|
|
groupdate adds scopes to ActiveRecord — group_by_year, group_by_month,
group_by_quarter — and handles partial periods, timezones, and sparse data
correctly.
Our labour_force_readings table uses integer year and month columns rather
than a single date column, so we cannot use group_by_year directly on this
model. We bucket by the year integer instead. The daily_activity_readings table
in Module 07 uses a proper date column — that is where groupdate earns its
place fully.
4.2 — The Service
|
|
The service groups by state, then by year, computing averages across all months in each year. Zeros are excluded from averages — a missing month should not drag down the annual figure.
4.3 — Controller and Routes
|
|
Add to config/routes.rb:
|
|
Add a scope to the model if not already present:
|
|
4.4 — Grouped Bar Chart
The main chart shows annual average employment by state. The ECharts toolbox provides stack/unstack, line/bar toggle, and save as image — no custom JavaScript needed.
|
|
<%# app/views/charts/labour_force.html.erb %>
<h1 class="text-2xl font-bold mb-6">Labour Force by State</h1>
<p class="text-neutral-500 mb-6 text-sm">
Annual average employed persons ('000), seasonally adjusted. Source: ABS Labour Force.
</p>
<%= render Components::Charts::LabourForce.new(readings: @readings) %>The toolbox sits inside the chart canvas — no custom buttons needed. Clicking the stack icon stacks the bars; clicking again unstacks them. The line icon switches between bar and line chart. Save as image downloads a PNG.
4.5 — The Toolbox
The ECharts toolbox is configured via the toolbox: option in Chart::Options.
All features use ECharts’ native icons and interactions:
|
|
| Feature | What it does |
|---|---|
magicType: ["bar", "line"] |
Toggles between bar and line chart |
magicType: ["stack"] |
Adds a stack/unstack toggle |
saveAsImage |
Downloads the chart as PNG |
restore |
Resets to the original chart state |
dataView |
Shows raw data in a table (read-only) |
Include only the features relevant to each chart — a pie chart has no use for
magicType: ["bar", "line"].
4.6 — Horizontal Bar Chart
Horizontal bars suit state comparisons where the category labels are more readable on the Y axis. In ECharts, horizontal orientation is achieved by swapping the axis types — no other changes needed.
|
|
<%# app/views/charts/labour_force_horizontal.html.erb %>
<h1 class="text-2xl font-bold mb-6">Employment by State — Latest Year</h1>
<p class="text-neutral-500 mb-6 text-sm">
Annual average employed persons ('000), seasonally adjusted. Source: ABS Labour Force.
</p>
<%= render Components::Charts::LabourForceHorizontal.new(readings: @readings) %>4.7 — Unemployment Rate Chart
The same service feeds a completely different chart type. The unemployment rate series demonstrates that services are chart-agnostic — they transform data, nothing more.
|
|
<%# app/views/charts/unemployment_rate.html.erb %>
<h1 class="text-2xl font-bold mb-6">Unemployment Rate by State</h1>
<p class="text-neutral-500 mb-6 text-sm">
Annual average unemployment rate (%), seasonally adjusted. Source: ABS Labour Force.
</p>
<%= render Components::Charts::UnemploymentRate.new(readings: @readings) %>The COVID-19 spike in 2020 is visible across all states. Tasmania and South Australia consistently track above the national average. The ACT and Northern Territory show the most volatility — small populations amplify statistical noise.
4.8 — Gallery Index
Add to app/views/charts/index.html.erb:
<%= render "charts/gallery_card",
title: "Labour Force by State",
description: "Annual average employment by state, 2012–2024. Toggle stacked/grouped or switch to line chart.",
path: charts_labour_force_path %>
<%= render "charts/gallery_card",
title: "Employment Snapshot",
description: "Latest year employment by state — horizontal bar chart.",
path: charts_labour_force_horizontal_path %>
<%= render "charts/gallery_card",
title: "Unemployment Rate by State",
description: "Annual average unemployment rate by state, 2012–2024.",
path: charts_unemployment_rate_path %>4.9 — What groupdate Does For Us
Our Labour Force data uses integer year and month columns so we bucket manually.
The daily_activity_readings table in Module 07 uses a proper date column — that
is where groupdate earns its place:
|
|
groupdate handles sparse data (missing dates), configurable week start, timezone
awareness, and range boundaries. Module 07 covers this properly.
4.10 — Module Summary
New files:
| File | Purpose |
|---|---|
app/services/stats/labour_force.rb |
Annual averages per state from monthly data |
app/views/components/charts/labour_force.rb |
Grouped bar chart with toolbox |
app/views/components/charts/labour_force_horizontal.rb |
Horizontal bar — latest year snapshot |
app/views/components/charts/unemployment_rate.rb |
Unemployment rate line chart |
Patterns introduced:
- Annual bucketing of monthly data
stack:onChart::Series::Barfor stacked bars- Horizontal bars via axis type swap (
x_axisvalue,y_axiscategory) - ECharts native toolbox —
magicType,saveAsImage,restore - Same service feeding multiple chart types
The toolbox replaces custom controls:
The ECharts toolbox handles stack/unstack, chart type switching, and PNG download
natively — no custom Stimulus controllers, no extra JavaScript. Add it to any chart
via the toolbox: option in Chart::Options.
Next: Module 05 — Scatter: Employment vs Participation Rate