CHARTS & MAPS · CHARTS
Mixed
Bars and lines on one canvas in plain SVG — dual axes with synced grids, goals per axis, plan vs actual, Pareto, volume vs rate, budget burn and forecast.THEME
01
Playground
Revenue & margin — combo, right axis, sync, labels, goals, stateCOMBO
RIGHT AXIS
ON RIGHT
SYNC GRID
LABELS
GOALS
STATE
$608krevenue, last 12 months27%average margin
NOW SPEAKING
CHART“Revenue and margin, last 12 months: Revenue as bars, Margin as a line on the right axis, Nov to Oct. Use left and right arrows to read each month.”
MONTH“Focus the chart and press → to read each month with both units”
TABLE“Table alternative: Revenue, Margin (%)”
RevenueMargin.tsx
1<ComboChart
2 data={monthly}
3 bars={["Revenue"]}
4 lines={[{ key: "margin", axis: "right" }]}
5 rightAxis={true} syncGrid={true}
6 valueLabels="line" goals={goals}
7 tooltip keyboard tableFallback
8/>
EVENT LOG
02
Variants
Plan vs actual, Pareto, volume & rate, budget burn, forecast, tablePlan vs actualbars = actual · step line = plan
Paretoclients by revenue · cumulative % · 80% line
Top 4 clients bring 68% of revenue
Volume & ratehours as bars · $/h as a line
Budget burnmonthly spend · cumulative · limit
Cumulative spend crosses the limit in Oct — cut or re-approve
Forecastfaded bars ahead · trend with a range
Nov–Jan are forecast: outlined, faded bars and a widening range
Chart or tabletwo units, two columns
03
States
Loading, empty, one series, error, incomparable scalesLoadingaxes first
Loading…
Emptyexplain, offer last year
No data for this periodNothing invoiced yet.
One series missingshow what exists, say what doesn’t
Margin isn’t available until costs are booked — showing revenue only
Errorkeep the frame
Couldn’t load the chartThe data service didn’t respond.
Incomparable scalesone axis, two units — misleading
Margin (%) is flattened against $ — add a right axis or split into two charts
04
Behavior
Two axes, colour, zero, draw orderTwo axesonly for different units
UseDifferent units: $ and %, hours and $/h
AvoidSame unit on two scales — it fakes a relationship
SyncAlign gridlines so both axes read the same rows
LimitOne series per axis, max 3 series total
Colour the axessay which is which
Axis textColoured like its series
TitlesREVENUE $ on the left, MARGIN % on the right
LegendL / R tag next to each name
TooltipEvery value with its unit
Zero & scalebars are honest, lines can zoom
BarsAlways from zero
LinesRight axis may zoom — label it clearly
GoalsDraw on the axis they belong to
ForecastOutlined, faded bars + a range
Draw orderwhat sits on top
BackGrid, range bands, bars
MiddleAreas and goal lines
FrontLines, points, labels
HoverA column highlight behind everything
05
In Avava
Finances, team load, client ParetoStudio finances · last 12 monthsrevenue · margin % · goals
Team load · 12 weekshours · utilization %
Client Paretowho brings the revenue
20% of clients (2 of 10) bring 43% of revenue
06
Rules & a11y
Mixed vs separate, screen readersMixed or two charts?pick by the question
Mixed
Two related measures, different units, same xRevenue $ and margin %
Two charts
Unrelated measures or > 3 seriesRevenue and headcount
Bars + line, one axis
Same unit: actual vs planRevenue vs target
Screen readerstwo units, said out loud
✓aria-roledescription="combination chart"aria-label says which series are bars, lines and on which axis
✓← → months, Home / End, EscEach month is announced with every unit
✓L / R tags in legend and tooltipAxis is never conveyed by colour alone
✓Table with a column per seriesUnits in the column headers
✓Warnings in text“Scales are incomparable” is a note, not a colour
DO✓Use a second axis only for a different unit✓Colour each axis like its series✓Sync gridlines across both axes✓Draw bars first, lines on top✓Show both units in the tooltip
DON’T✕Put two $ series on two scales✕Start bars above zero✕Mix more than 3 series✕Hide which axis a line belongs to✕Imply correlation just because lines cross