Charts/Category charts
Bullet
<Bullet /> · 10 examples
A compact bar showing one measure against a target and three performance bands.
Overview
Dashboards used to be full of gauges: round dials with a needle, a red zone, a green zone, and a quiet sense that someone at the software company had once seen a car. A gauge uses a large square of screen to show one number. Put six of them side by side and you have used the whole page, learned six numbers, and still cannot tell which is worst.
Stephen Few designed the bullet graph in the mid-2000s as a replacement, and the design is very sensible. A single bar shows the value. A short tick across it marks the target. Behind both, three bands of grey, from dark to light, mark poor, fair and satisfactory ranges. All of that fits in one thin horizontal strip, so you can stack ten of them and compare every KPI in one glance.
The name is a joke the designer never intended. The thick bar and the small tick resemble a bullet, which is the only violent thing about it. Everything else is a calm summary of how things are going.
Props
API
<Bullet data={kpis} name={|k: &Kpi| k.name} value={|k: &Kpi| k.value} target={|k: &Kpi| k.target} ranges={|k: &Kpi| k.bands} />| Prop | Type | Default |
|---|---|---|
value | Fn(&T) -> f64 | required |
target | Fn(&T) -> f64: drawn as a short cross line | none |
ranges | Fn(&T) -> [f64; 3]: the upper ends of the poor, satisfactory and good bands, smallest first | none |
color | colour of the value bar | the first series colour |
target_color | colour | the bad colour |
value_axis | AxisConfig | starts at 0 |
horizontal | true |
The bands are drawn as three shades of grey behind a narrower value bar.
Run them
10 examples
Press Run to load an example into the live render at the top of the page. Open one to read its code.
How to read it
- 01Find the thick coloured bar. Its end is the actual value.
- 02Find the thin tick across the row. If the bar passes it, the target is met, if the bar falls short, the gap is visible.
- 03Look at the grey bands behind. Dark means poor, medium means fair, light means satisfactory, so the shade the bar ends in tells you how good the result is.
- 04Compare rows by their shape. Rows share one axis, so a longer bar really is a bigger number.
- 05Hover a row for the value, the target and the band edges.
When to use it, and when not to
Reach for it when
- You report several KPIs together and each has a target and a sense of good and bad: sales against quota, uptime against SLA, defects against tolerance.
- You want a dashboard that is dense but still readable, with a dozen measures in one panel.
- The audience wants to know not just whether a target was hit but how comfortably, which the bands show.
Skip it when
- There is no target and no sense of a good range. Then a plain bar or a lollipop does the job with less decoration.
- The measures are on very different scales in the same chart. Each row shares a single axis, so a metric in the thousands will flatten one in single digits. Chart them separately, or normalise to a percentage of target.
- You need to show history. A bullet is a snapshot. Use a stat with a sparkline or a time series.
- A single value, shown large, is the whole message. Use gauge or stat.
The math behind it
One row, five marks
Each row has a name, a measured value , an optional target , and optional three band edges given as an array in that order, smallest first. They are the upper ends of the poor, fair and satisfactory ranges.
The bands are bars drawn from the baseline, widest first, one on top of the other. The largest band, ending at , is the lightest and sits at the back. The next, ending at , is darker, and the poor band, ending at , is the darkest and drawn in front. So the visible stripe of each colour is the difference between neighbouring edges, though the data holds cumulative values.
The value bar and the target tick
The value is a bar from the baseline to , in the series colour, at about 30% of the slot thickness: narrower than the bands, so the bands read as a background. The target is a thin tick across the row at . Its thickness is a fixed fraction of the data range, which is where is the largest finite value among the measures, targets and top band edges in the whole chart.
Then the tick is a small bar of height whose lower end is , centred on the target. The value axis defaults to a minimum of zero, since the value is a bar and bars must start there. With no ranges, the bands are not drawn, and with no target the tick is omitted.
Real life usage
Six dials, one red number
Nkechi ran customer support for a payments company, and her Monday dashboard had six gauges. They were large, glossy and round, and she had inherited them from a predecessor who had clearly loved speedometers. Each showed one number: first response time, resolution rate, backlog, CSAT, escalations and a thing called Happy Index which nobody could define.
The trouble began when the vice-president asked which of the six needed attention. Nkechi looked at the dials. Three were in the green. Two were in what might be described as olive. One was a needle at an angle that could be read either as bad or as the artist's choice.
Gauges carry a surprising amount of ceremony for the information they provide. You read the needle, find the zone, remember what the zone means, and then try to compare it with five other needles, none of which are drawn to the same scale of dread.
She rebuilt the panel with <Bullet>, one row per metric, with the value, the quarterly target, and three bands that her team had agreed on years ago and never drawn. The six rows fitted in one third of the space the gauges had used.
Now it was quick. The bars for response time and CSAT ended in the lightest band, well past their ticks. Backlog was a bar that stopped inside the dark band, a long way short of its tick. Escalations, which had looked fine as a needle, was in the fair band and drifting toward the dark one.
The vice-president pointed at the backlog row before anyone spoke. The team added two agents on the late shift and, within five weeks, backlog moved into the fair band and its bar reached the target tick by the end of the quarter. The Happy Index was retired, quietly, and without a funeral.
A gauge shows you a number. A bullet shows you a number, the goal, and whether you ought to worry.
Pitfalls
- Band order. Pass
rangesas[poor, fair, satisfactory]upper ends, smallest first. The bands are drawn as nested bars, so passing them out of order hides one of them. - Higher is not always better. Bands are shaded dark for the lowest range, which assumes low is poor. For error rates or latency, reverse the meaning in your head or in a label.
- A zero baseline is assumed. The value axis starts at zero by default, and the bars are anchored there. Setting a higher minimum cuts the bars and misleads.
- Target tick scale. The tick is sized from the largest number in the whole chart, so one very large row makes every tick thinner on the others.
From around the web