Grouped bar chart
Side-by-side comparison of 2–5 series within each X-band — e.g. revenue per region per quarter. Each outer band (a quarter) is subdivided into one inner band per series (a region).
Demo — Apollo crewed missions per year, 1968–1972
The plain-bar variant (?chart=bar) below plots crewed Apollo
missions flown per calendar year. 1969 carries four flights
(Apollo 9 LM rehearsal, Apollo 10 lunar reconnaissance, Apollo
11 first landing, Apollo 12 second landing) — the program's
single most ambitious year. By 1972 only Apollo 17 flew.
Source: Apollo program — Wikipedia
Grouped variant — Apollo annual budget by NASA centre
The same Apollo dataset, sliced differently. Annual program outlays ($B, 1973 dollars) for five reference years (1962, 1964, 1966, 1969, 1972), grouped by the three centres that owned the spend: Marshall (Saturn V), Manned Spacecraft Center (CSM + LM), and Kennedy (launch ops + tracking). The 1966 peak matches the late-stage Saturn V flight-hardware build right before Apollo 4's all-up test.
Source: Apollo program — Costs — Wikipedia
Public surface
The grouped layout is one extra encoding on top of the standard bar chart:
let plot = Plot::new(rows)
.mark(Mark::Bar { value_labels: false })
.encode(plot::x("quarter", ScaleKind::Band))
.encode(plot::y("revenue", ScaleKind::Linear))
.encode(plot::color("region"))
.encode(plot::x_offset("region"));
Adding plot::x_offset(field) re-bands the X axis: each unique
value of field becomes a sub-band within the outer X band.
Layout
The outer X band (e.g. "Q1") spans some pixel range
[bx0, bx1]. The grouped layout constructs an inner
BandScale over the distinct XOffset categories with that
range as its pixel range and a 10% inner padding, then asks for
the sub-band's [ix0, ix1].
Pairing with Legend
When the same column drives both Color and XOffset,
Plot::legend
returns a legend whose colours match the bar segments exactly.
Use the legend chapter for placement.
Theme integration
Grouped bars reuse the bar palette + theme. Inner band padding
is fixed at 0.10 today; an explicit PlotTheme.bar_inner_padding
field lands when the value needs to be customisable.