@blueprint-chart/docs 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/dist/api.d.ts +13 -0
  4. package/dist/api.js +29 -0
  5. package/dist/manifest.json +242 -0
  6. package/package.json +63 -0
  7. package/src/charts/area-stacked.md +64 -0
  8. package/src/charts/area.md +65 -0
  9. package/src/charts/bar-grouped.md +60 -0
  10. package/src/charts/bar-horizontal.md +71 -0
  11. package/src/charts/bar-multi.md +64 -0
  12. package/src/charts/bar-split.md +61 -0
  13. package/src/charts/bar-stacked.md +62 -0
  14. package/src/charts/bar-vertical.md +71 -0
  15. package/src/charts/column-stacked.md +57 -0
  16. package/src/charts/donut.md +66 -0
  17. package/src/charts/index.md +36 -0
  18. package/src/charts/line-multi.md +64 -0
  19. package/src/charts/line.md +65 -0
  20. package/src/charts/pie.md +63 -0
  21. package/src/guide/accessibility.md +196 -0
  22. package/src/guide/data-transforms.md +191 -0
  23. package/src/guide/dsl-editor.md +218 -0
  24. package/src/guide/embed.md +208 -0
  25. package/src/guide/getting-started.md +159 -0
  26. package/src/guide/palettes.md +207 -0
  27. package/src/guide/scenes.md +223 -0
  28. package/src/handbook/accessibility.md +109 -0
  29. package/src/handbook/annotations.md +143 -0
  30. package/src/handbook/anti-patterns.md +85 -0
  31. package/src/handbook/axes.md +116 -0
  32. package/src/handbook/choosing.md +120 -0
  33. package/src/handbook/color.md +141 -0
  34. package/src/handbook/design-principles.md +111 -0
  35. package/src/handbook/frame-elements.md +98 -0
  36. package/src/handbook/index.md +91 -0
  37. package/src/handbook/labels.md +117 -0
  38. package/src/handbook/tooltips.md +98 -0
  39. package/src/handbook/typography.md +93 -0
  40. package/src/reference/api/index.md +245 -0
  41. package/src/reference/dsl/annotations.md +135 -0
  42. package/src/reference/dsl/index.md +137 -0
  43. package/src/reference/dsl/properties.md +79 -0
  44. package/src/reference/dsl/scenes-and-transforms.md +97 -0
  45. package/src/reference/index.md +18 -0
@@ -0,0 +1,223 @@
1
+ ---
2
+ title: Scenes
3
+ ---
4
+
5
+ # Scenes
6
+
7
+ > Same chart, different states — composed into a story that a reader can step through.
8
+
9
+ ## Why this matters
10
+
11
+ Journalism rarely sits still on a single chart. A finding has a build-up, a turn, and a punchline. In Blueprint Chart, a **scene** is a named visualisation state — the same chart with different data, highlighting, annotations, or styling — and a sequence of scenes is the chart's **story**. You write scenes in the same `.bpc` document, and the runtime gives the reader Previous / Next controls (or your own UI) to walk through them.
12
+
13
+ ## Quickstart
14
+
15
+ A bar chart with three narrative beats — each one highlights a different country:
16
+
17
+ ```bpc
18
+ chart bar-horizontal {
19
+ title = "Five nations produce 80% of global CO₂"
20
+ description = "Annual emissions in billion tonnes, 2023"
21
+ source = "Global Carbon Project"
22
+ sourceUrl = "https://globalcarbonproject.org"
23
+ sort = descending
24
+ valueLabels = true
25
+ horizontalGridStyle = none
26
+ showVerticalAxis = true
27
+ showVerticalTicks = false
28
+ verticalGridStyle = none
29
+
30
+ data {
31
+ "China" = 11.90
32
+ "United States" = 4.78
33
+ "India" = 2.88
34
+ "Russia" = 1.78
35
+ "Japan" = 1.02
36
+ }
37
+
38
+ scene "China spotlight" {
39
+ title = "China emits more than the US and India combined"
40
+
41
+ highlight "China"
42
+ }
43
+
44
+ scene "India rising" {
45
+ title = "India surpassed the EU in 2023"
46
+
47
+ highlight "India"
48
+ }
49
+
50
+ scene "Japan declining" {
51
+ title = "Japan's emissions fell 20% from their peak"
52
+
53
+ highlight "Japan"
54
+ }
55
+ }
56
+ ```
57
+
58
+ ::: tip From the sample library
59
+ This is `packages/lib/src/samples/co2-emissions-story.bpc` verbatim — three scenes, each one re-titling the chart and shifting the highlight to a new country. The base data stays the same; only the framing changes.
60
+ :::
61
+
62
+ Open this in the editor to see the scene timeline appear automatically; embed it on a page and readers get a Previous / Next nav.
63
+
64
+ ## How it works
65
+
66
+ A scene block accepts the same member set as the top-level chart, **plus** annotation-visibility verbs. At parse time, each `scene` becomes a `SceneNode` in the AST. The DSL converter merges scene members on top of the base chart to produce the **effective** `ChartData` and `ChartOptions` for that scene.
67
+
68
+ At render time:
69
+
70
+ 1. The runtime collects the chart's scenes into a `SceneDefinition[]`.
71
+ 2. `createSceneController(container, scenes, onSceneChange)` injects a small `<nav>` (Previous / Next / counter) into the container.
72
+ 3. On every scene change, the callback re-renders the chart with `transition = true`, which triggers the motion helpers (`snapshotForFadeOut`, `commitFadeOut`, `fadeIn`) and animates the crossfade.
73
+ 4. `goTo(index)` clamps and wraps so `goTo(-1)` cycles to the last scene.
74
+
75
+ The pipeline that runs per scene is the same eleven-step sequence documented in [Embedding](/guide/embed) and the DSL spec — scene overrides are merged at step 3 (transforms), so everything downstream sees the post-scene state.
76
+
77
+ ## Recipes
78
+
79
+ ### Highlight a different point per scene
80
+
81
+ The short-form `highlight "<name>"` is the workhorse. Drop one per scene and the rest of the chart greys out:
82
+
83
+ ```bpc
84
+ scene "China spotlight" {
85
+ title = "China emits more than the US and India combined"
86
+
87
+ highlight "China"
88
+ }
89
+
90
+ scene "India rising" {
91
+ title = "India surpassed the EU in 2023"
92
+
93
+ highlight "India"
94
+ }
95
+ ```
96
+
97
+ ::: tip From the sample library
98
+ Two adjacent scenes from `packages/lib/src/samples/co2-emissions-story.bpc`. Each scene retitles the chart and shifts the spotlight without touching the base data.
99
+ :::
100
+
101
+ ### Replace data wholesale in a scene
102
+
103
+ Any scene can carry its own `data` block, which **replaces** the base data for that scene's render. The Bulgaria scene from `farm-compass` drops the EU-wide aggregate in favour of a country-specific time series, and keeps the same `area-stacked` chart type:
104
+
105
+ ```bpc
106
+ scene "Bulgaria: subsidies explode" {
107
+ title = "Subsidies to Bulgarian farmers, million euros"
108
+ description = "85% of Bulgarian subsidies are direct payments — the highest share among new members"
109
+
110
+ data {
111
+ _series = "Indirect subsidies","Direct subsidies"
112
+ "2000" = 0,5
113
+ "2004" = 0,67
114
+ "2007" = 59,250
115
+ "2010" = 79,466
116
+ "2013" = 132,852
117
+ "2015" = 213,677
118
+ }
119
+
120
+ highlight "Direct subsidies"
121
+ }
122
+ ```
123
+
124
+ ::: tip From the sample library
125
+ Trimmed scene from `packages/lib/src/samples/farm-compass.bpc` (full sample has the 2000–2015 yearly series). The scene swaps data and keeps the parent chart's `area-stacked` type.
126
+ :::
127
+
128
+ ### Switch chart type mid-story
129
+
130
+ A scene can override the chart type with `type =`. The same `farm-compass` story leaves the parent `area-stacked` chart and pivots to a `line` for the "farms grew" beat, then back to an `area-stacked` later on:
131
+
132
+ ```bpc
133
+ scene "Bulgarian farms grew" {
134
+ title = "Average farm size in Bulgaria quadrupled"
135
+ description = "Average farm size in hectares"
136
+ type = line
137
+
138
+ data {
139
+ "2005" = 5
140
+ "2007" = 6
141
+ "2010" = 12
142
+ "2013" = 18
143
+ }
144
+ }
145
+ ```
146
+
147
+ ::: tip From the sample library
148
+ Scene #5 of `packages/lib/src/samples/farm-compass.bpc`. The story changes chart type three times across nine scenes — `area-stacked` → `line` → `area` → `area-stacked` → bar — all from one document.
149
+ :::
150
+
151
+ ### Hide an annotation in a later scene
152
+
153
+ Use `hide_annotation`, `hide_range`, or `hide_note` with the annotation's id to peel things back as the story progresses:
154
+
155
+ ```bpc
156
+ annotation "2015" {
157
+ id = "paris"
158
+ text = "Paris Agreement"
159
+ }
160
+
161
+ scene "Without Paris callout" {
162
+ hide_annotation "paris"
163
+ }
164
+ ```
165
+
166
+ To bring it back later, use `show_annotation "paris"` in a subsequent scene.
167
+
168
+ ### Drive playback from your own UI
169
+
170
+ The controller is decoupled from the nav DOM it inserts — you can ignore the built-in buttons and call `next()`, `previous()`, or `goTo(index)` from any custom UI:
171
+
172
+ ```ts
173
+ import { createSceneController } from '@blueprint-chart/lib/dist/runtime'
174
+
175
+ const controller = createSceneController(container, scenes, (scene, index) => {
176
+ renderChart(canvas, scene.data, true)
177
+ })
178
+
179
+ document.querySelector('#my-next-button')!.addEventListener('click', () => {
180
+ controller.next()
181
+ })
182
+
183
+ // Programmatic jump:
184
+ controller.goTo(2)
185
+ ```
186
+
187
+ Call `controller.destroy()` to remove the injected nav when tearing the chart down.
188
+
189
+ ## API surface
190
+
191
+ Exported from `@blueprint-chart/lib/dist/runtime`:
192
+
193
+ | Symbol | One-liner |
194
+ | --- | --- |
195
+ | `createSceneController(container, scenes, onSceneChange)` | Build a scene controller, inject Previous / Next nav, call back on every scene change. |
196
+ | `SceneDefinition` (type) | `{ name: string, data?: Record<string, unknown> }` — one scene's payload. |
197
+ | `SceneController` (type) | Returned object with `currentScene`, `totalScenes`, `next()`, `previous()`, `goTo(index)`, `destroy()`. |
198
+ | `createStepController` / `StepDefinition` / `StepController` | Deprecated aliases retained for backward compatibility — new code should use the `Scene*` names. |
199
+
200
+ Motion helpers used internally during scene transitions (all exported from `@blueprint-chart/lib`):
201
+
202
+ | Symbol | One-liner |
203
+ | --- | --- |
204
+ | `getTransitionDuration()` | Canonical fade duration shared with the editor's UI transitions. |
205
+ | `snapshotForFadeOut(container)` | Capture the outgoing DOM for fade-out. |
206
+ | `commitFadeOut(snapshot)` | Animate the snapshot out. |
207
+ | `fadeIn(container)` | Animate the new render in. |
208
+ | `getCachedChart(container)` | Last render, for diff-based interpolation. |
209
+
210
+ DSL converter helpers (also exported from `@blueprint-chart/lib`):
211
+
212
+ | Symbol | One-liner |
213
+ | --- | --- |
214
+ | `extractSceneOverrides(ast)` | Pull each scene's merged `ChartData` / `ChartOptions` from a parsed AST. |
215
+ | `SceneNode` (type) | AST node for a `scene` block. |
216
+
217
+ See the full list in the [API reference](/reference/api/).
218
+
219
+ ## See also
220
+
221
+ - [BPC DSL — Scenes](/reference/dsl/scenes-and-transforms#scenes) for the source-level grammar.
222
+ - [Embedding charts](/guide/embed) for how to drop a scenes-driven chart on a page.
223
+ - [API reference](/reference/api/#runtime-entrypoint) for the runtime entry-point symbols.
@@ -0,0 +1,109 @@
1
+ ---
2
+ title: Accessibility
3
+ ---
4
+
5
+ # Accessibility
6
+
7
+ > Accessible charts are honest charts. CVD simulation, sufficient contrast, meaningful alt text, keyboard and screen-reader support, legible typography, and — above all — never encoding information in a single visual channel.
8
+
9
+ ## Color vision deficiency
10
+
11
+ Around **8% of men** and **0.5% of women** have some form of color vision deficiency.
12
+
13
+ - **Never rely on color alone** to convey meaning — combine with shape, pattern, label, or position
14
+ - Ensure colors vary enough in **lightness** — convert your palette to grayscale as a quick test
15
+ - Blue-orange is the safest hue combination for deuteranopia / protanopia
16
+ - Avoid red-green combinations without additional encoding
17
+ - Achieve at least **3:1 contrast ratio** between adjacent colors (WCAG)
18
+ - Test with simulators: Color Oracle, Coblis, Sim Daltonism, Firefox colorblind addon
19
+
20
+ ## Text contrast
21
+
22
+ - Minimum **4.5:1 contrast ratio** for normal text (WCAG AA)
23
+ - Minimum **3:1** for large text (18px+ bold or 24px+ regular)
24
+ - Higher contrast needed for small or distant chart elements
25
+
26
+ ## Alt text for charts
27
+
28
+ Every chart needs two levels of text alternative:
29
+
30
+ 1. **Short alt text** — Identifies the chart type, subject, and scope. *Example: "Bar chart showing quarterly revenue for 2024 by product line"*
31
+ 2. **Long description** — Full textual representation of essential data. Can be a linked data table, a `<figcaption>`, or content referenced via `aria-describedby`
32
+
33
+ ## Keyboard and screen reader support
34
+
35
+ - Interactive elements (tooltips, filters) must be keyboard-accessible
36
+ - Use semantic HTML (`<figure>`, `<figcaption>`) to wrap charts
37
+ - Provide data tables as an alternative view for complex interactive charts
38
+ - Use `aria-describedby` to connect charts to their descriptions
39
+
40
+ ## Font accessibility
41
+
42
+ - Minimum **12px** for chart text
43
+ - Sans-serif fonts with distinct character shapes (l vs. 1 vs. I)
44
+ - Avoid thin / light font weights for data labels
45
+ - Consider **Atkinson Hyperlegible** for maximum legibility
46
+
47
+ ## Multiple encoding
48
+
49
+ ::: warning
50
+ **Never encode information in a single visual channel.** Combine at least two.
51
+ :::
52
+
53
+ - Color + shape (circles vs. triangles)
54
+ - Color + pattern (solid vs. hatched)
55
+ - Color + label (direct text identification)
56
+ - Position + size + color (scatter / bubble charts)
57
+
58
+ ## How Blueprint Chart applies accessibility
59
+
60
+ Blueprint Chart ships a concrete accessibility toolkit:
61
+
62
+ - `wcagContrastRatio` — computes WCAG contrast between two colors
63
+ - `simulateCvdColor` — applies deuteranopia / protanopia / tritanopia simulation
64
+ - `checkCvdColors` — validates that a palette is safe across CVD types
65
+
66
+ These power the editor's live accessibility checks and the palette pickers in the UI. See the [API reference](/reference/api/) for the full helper surface.
67
+
68
+ ```ts
69
+ import { wcagContrastRatio, checkCvdColors } from '@blueprint-chart/lib'
70
+
71
+ wcagContrastRatio('#2563A0', '#ffffff') // 5.13 — passes WCAG AA for normal text
72
+ checkCvdColors(['#2563A0', '#F26A1F']) // safe across deuteranopia / protanopia / tritanopia
73
+ ```
74
+
75
+ ## Worked example: lightness variation beats hue variation
76
+
77
+ ```bpc
78
+ chart bar-vertical {
79
+ title = "Brazil produces more coffee than the next three countries combined"
80
+ colorPalette = "Harvey"
81
+ valueLabels = true
82
+
83
+ data {
84
+ "Brazil" = 66.4
85
+ "Vietnam" = 29
86
+ "Colombia" = 11.4
87
+ "Indonesia" = 9.9
88
+ }
89
+
90
+ colorize "Brazil" {
91
+ color = "#a4432d"
92
+ }
93
+ }
94
+ ```
95
+
96
+ ::: info From `packages/lib/src/samples/coffee-production.bpc`
97
+ Coffee uses two encodings for the highlighted bar: a distinct hue (`#a4432d` red-brown vs. the muted Harvey palette) and clear *lightness* contrast against its neighbours. Convert the chart to greyscale and Brazil still reads as the darkest bar — the second encoding (lightness) carries the story even when CVD removes the first (hue). Compare with `valueLabels = true`, which adds a *third* encoding (the literal number).
98
+ :::
99
+
100
+ ## Palette catalogue and CVD utilities
101
+
102
+ Blueprint Chart ships 50+ palettes in `packages/lib/src/charts/palettes.ts`; each one is interpolated through HCL so adjacent colours vary in lightness as well as hue. The CVD simulation and validation helpers live in `packages/lib/src/charts/colorblind.ts`. Together they power the editor's live accessibility checks — any palette referenced by `colorPalette = "<name>"` in a `.bpc` file is run through `checkCvdColors` automatically.
103
+
104
+ ## See also
105
+
106
+ - [Color & Palettes](/handbook/color)
107
+ - [Typography](/handbook/typography)
108
+ - [Tooltips & Interaction](/handbook/tooltips)
109
+ - [Design Principles](/handbook/design-principles)
@@ -0,0 +1,143 @@
1
+ ---
2
+ title: Annotations
3
+ ---
4
+
5
+ # Annotations
6
+
7
+ > Annotations guide the reader to the story in the data. They explain design elements, highlight significant values, and provide context the chart alone cannot convey. Used well, they do most of the storytelling.
8
+
9
+ ## Purpose
10
+
11
+ Annotations guide the reader to the story in the data. They explain design elements, highlight significant values, and provide context that the chart alone cannot convey.
12
+
13
+ A chart without annotations presents data. A chart *with* annotations tells a story.
14
+
15
+ ## Types of annotations
16
+
17
+ | Type | Description | Use for |
18
+ |------|-------------|---------|
19
+ | **Reference line (horizontal)** | Line at a specific y-value | Averages, targets, benchmarks, thresholds |
20
+ | **Reference line (vertical)** | Line at a specific x-value | Events in time, policy changes, milestones |
21
+ | **Range band (horizontal)** | Shaded region between two y-values | Acceptable zones, confidence intervals |
22
+ | **Range band (vertical)** | Shaded region between two x-values | Time periods (recessions, campaigns) |
23
+ | **Point annotation** | Marker + label at a specific data point | Outliers, peaks, significant individual values |
24
+ | **Callout** | Label with connector line | Explanations positioned away from crowded areas |
25
+
26
+ ## Best practices
27
+
28
+ - Maximum **3-4 annotations per chart** to avoid overwhelming readers
29
+ - Position explanatory text as close to the relevant data as possible
30
+ - Use **two text hierarchy levels** within annotations (e.g., bold primary, regular secondary) — not more
31
+ - Use text outlines when annotations overlay grid lines
32
+ - On mobile, hide less important annotations or move them below the chart
33
+ - Write annotations that add context beyond what the data shows ("why" not just "what")
34
+
35
+ ## Annotations as storytelling
36
+
37
+ ::: tip
38
+ "If everything is emphasized, nothing is." Prioritize ruthlessly. The annotation should match the chart's headline — reinforce the main point, don't dilute it with tangential observations.
39
+ :::
40
+
41
+ A good annotation reads like a caption to a photograph: it tells the reader what matters here and why. Avoid restating what the axis already shows.
42
+
43
+ ::: info Example
44
+ **Bad:** "March: 2,300 units" (redundant with the data label)
45
+
46
+ **Good:** "New packaging launched March 3 — unit sales jumped 40%"
47
+ :::
48
+
49
+ ## How Blueprint Chart applies annotations
50
+
51
+ Blueprint Chart implements annotations as first-class citizens: **Point**, **Range**, and **Free** annotations are part of the DSL grammar and the rendering pipeline. Annotations are ordered and rendered above the chart geometry but below tooltips, so they sit visually in the foreground without interfering with hover interaction.
52
+
53
+ ```bpc
54
+ chart line {
55
+ title = "Unit sales jumped after new packaging launched"
56
+
57
+ data {
58
+ "Jan" = 1600
59
+ "Feb" = 1700
60
+ "Mar" = 2300
61
+ "Apr" = 2350
62
+ "May" = 2420
63
+ }
64
+
65
+ annotation point {
66
+ at = "Mar"
67
+ label = "New packaging launched March 3"
68
+ }
69
+ }
70
+ ```
71
+
72
+ See the [BPC DSL Specification](/reference/dsl/annotations) for the full annotation grammar.
73
+
74
+ ## Worked example: a point annotation tied to a peak
75
+
76
+ ```bpc
77
+ chart line {
78
+ title = "Bitcoin surged past $90,000 in 2024"
79
+ description = "USD, year-end closing price"
80
+ source = "CoinGecko"
81
+ colors = "#f7931a"
82
+
83
+ data {
84
+ "2020" = 28949
85
+ "2021" = 46306
86
+ "2022" = 16547
87
+ "2024" = 93429
88
+ }
89
+
90
+ annotation "2021" {
91
+ text = "All-time high cycle"
92
+ dy = -12
93
+ showArrow = true
94
+ }
95
+ }
96
+ ```
97
+
98
+ ::: info From `packages/lib/src/samples/bitcoin-price.bpc`
99
+ The annotation is keyed by the same x-value the data uses (`"2021"`), placed `-12` pixels above the point and connected with `showArrow`. One annotation, one observation — the chart stays under the 3–4 annotation ceiling and the label sits in the negative space above the data, not on top of the line.
100
+ :::
101
+
102
+ ## Worked example: a callout with curved leader line
103
+
104
+ ```bpc
105
+ chart bar-vertical {
106
+ title = "China emits more CO₂ than the US and India combined"
107
+ description = "Annual emissions in billion tonnes, 2023"
108
+ colors = "#abb8c3"
109
+ valueLabels = true
110
+
111
+ data {
112
+ "China" = 11.9
113
+ "United States" = 4.78
114
+ "India" = 2.88
115
+ "Russia" = 1.78
116
+ }
117
+
118
+ colorize "China" {
119
+ color = "#e15759"
120
+ }
121
+
122
+ annotation "India" {
123
+ text = "Surpassed EU in 2023"
124
+ showLine = true
125
+ anchorDirection = N
126
+ textOffsetX = 66
127
+ textOffsetY = -41
128
+ lineStyle = curve-left
129
+ showArrow = true
130
+ }
131
+ }
132
+ ```
133
+
134
+ ::: info From `packages/lib/src/samples/co2-emissions.bpc`
135
+ A callout adds the *why* alongside the data ("Surpassed EU in 2023") — a sentence that the bar height alone cannot communicate. `lineStyle = curve-left` plus the text offsets keep the label well clear of the bars; `anchorDirection = N` attaches the leader line to the top of the "India" bar.
136
+ :::
137
+
138
+ ## See also
139
+
140
+ - [Frame Elements](/handbook/frame-elements)
141
+ - [Labels & Legends](/handbook/labels)
142
+ - [Design Principles](/handbook/design-principles)
143
+ - [BPC DSL Specification](/reference/dsl/annotations)
@@ -0,0 +1,85 @@
1
+ ---
2
+ title: Anti-Patterns
3
+ ---
4
+
5
+ # Anti-Patterns
6
+
7
+ > A catalog of what goes wrong: misleading practices that distort the truth, design anti-patterns that obscure the story, and the statistical integrity rules that keep charts honest.
8
+
9
+ ## Misleading practices
10
+
11
+ | Anti-pattern | Why it misleads | Fix |
12
+ |--------------|-----------------|-----|
13
+ | Truncated y-axis on bar charts | Exaggerates small differences | Start at zero |
14
+ | Dual y-axes | Arbitrary scale alignment implies false correlation | Side-by-side charts or indexed values |
15
+ | 3D effects | Tilted surfaces distort perceived values | Use flat 2D charts |
16
+ | Cherry-picked time ranges | Supports a narrative without full context | Show complete timeframe; note any filtering |
17
+ | Bubble size by radius | Exponential area distortion | Size by area |
18
+ | Unnormalized choropleth | Shows population density, not the intended variable | Normalize per capita / per unit |
19
+ | Rainbow color scales | Perceptually non-uniform; meaningless ordering | Use sequential or diverging palettes |
20
+
21
+ See [Axes & Grid Lines](/handbook/axes) for the baseline rules behind the first row, and [Color & Palettes](/handbook/color) for palette guidance that prevents the last two.
22
+
23
+ ## Design anti-patterns
24
+
25
+ | Anti-pattern | Problem | Fix |
26
+ |--------------|---------|-----|
27
+ | Spaghetti chart | Too many overlapping lines | Highlight key lines; grey the rest; small multiples |
28
+ | Pie chart with 10+ slices | Unreadable small slices | Use bar chart or group into "Other" |
29
+ | Decorative color | Color without meaning adds noise | Use grey for non-meaningful elements |
30
+ | Legend far from data | Forces eye-travel; increases cognitive load | Direct labeling |
31
+ | Rotated axis labels | Hard to read | Abbreviate labels or use horizontal bars |
32
+ | Over-annotation | Competing for attention dilutes the message | Maximum 3-4 annotations; prioritize |
33
+ | Missing context | Data without comparison has no story | Add reference lines, targets, time comparisons |
34
+ | Stacking many small segments | Impossible to read individual values | Group small segments; use direct comparison |
35
+
36
+ See [Labels & Legends](/handbook/labels) for direct-labeling technique and [Annotations](/handbook/annotations) for the 3–4 annotation ceiling.
37
+
38
+ ## Statistical integrity
39
+
40
+ - **Start axes at zero** for area / bar charts unless there is a compelling, stated reason not to
41
+ - **Avoid implying causation from correlation** (scatter plots show association only)
42
+ - Show **confidence intervals and error bars** when data has uncertainty
43
+ - Don't obscure sample size (**box plots hide it**; add individual points for small N)
44
+ - **Tables are valid** — sometimes better than charts for conveying precise values
45
+
46
+ ## Worked example: a shared baseline instead of three deceptive single-bar charts
47
+
48
+ A frequent anti-pattern is splitting a comparison across three charts with different y-axis ranges — each one tuned to "look interesting" in isolation. The honest alternative is one chart with a shared scale, so identical bar lengths mean identical values:
49
+
50
+ ```bpc
51
+ chart bar-split {
52
+ title = "Singapore leads the world in all three PISA 2022 subjects"
53
+ description = "Mean scores in Mathematics, Reading, and Science for 15-year-olds"
54
+ source = "OECD PISA 2022"
55
+ valueLabels = true
56
+ sharedScale = true
57
+
58
+ data {
59
+ _series = "Mathematics","Reading","Science"
60
+ "Singapore" = 575,543,561
61
+ "Japan" = 536,516,547
62
+ "Korea" = 527,515,528
63
+ "Estonia" = 510,511,526
64
+ "Canada" = 497,507,515
65
+ "Australia" = 487,498,507
66
+ }
67
+ }
68
+ ```
69
+
70
+ ::: tip Done right
71
+ `sharedScale = true` forces every panel onto the same baseline-zero axis, so the eye can compare Mathematics directly against Reading directly against Science. `valueLabels = true` then exposes the exact number, removing any temptation to truncate the axis for visual drama. This is the corrective pattern for the "truncated y-axis", "dual y-axes", and "missing context" rows above. From `packages/lib/src/samples/pisa-scores.bpc`.
72
+ :::
73
+
74
+ ## The meta-rule
75
+
76
+ ::: tip
77
+ Every anti-pattern traces back to a design principle being violated. If a chart feels wrong, walk back through the [design principles](/handbook/design-principles) — purposefulness, clarity, data-ink, restraint, consistency, comparison. One of them will be out of place.
78
+ :::
79
+
80
+ ## See also
81
+
82
+ - [Design Principles](/handbook/design-principles)
83
+ - [Choosing the Right Chart](/handbook/choosing)
84
+ - [Axes & Grid Lines](/handbook/axes)
85
+ - [Color & Palettes](/handbook/color)
@@ -0,0 +1,116 @@
1
+ ---
2
+ title: Axes & Grid Lines
3
+ ---
4
+
5
+ # Axes & Grid Lines
6
+
7
+ > When zero matters, when it doesn't, how grid lines should whisper rather than shout, how to format numbers, when to use logarithmic scales, and how aspect ratio silently changes a chart's story.
8
+
9
+ ## Baseline rules
10
+
11
+ | Chart type | Must start at zero? | Reason |
12
+ |------------|---------------------|--------|
13
+ | Bar / column | **Yes** | Bar length encodes the value |
14
+ | Stacked bar | **Yes** | Area encodes the value |
15
+ | Area chart | **Yes** | Filled area encodes magnitude |
16
+ | Line chart | **No** | Position (not length) encodes the value |
17
+ | Scatter plot | **No** | Position encodes the value |
18
+
19
+ ::: warning
20
+ Truncating the y-axis on a bar or area chart visually exaggerates differences. This is the single most common deceptive pattern in the wild. See [Anti-Patterns](/handbook/anti-patterns).
21
+ :::
22
+
23
+ ## Grid lines
24
+
25
+ - Grid lines should be **subtle**: light grey, thin (0.5–1px)
26
+ - Y-axis grid lines are generally more useful than x-axis grid lines
27
+ - Remove grid lines entirely when value labels are shown directly on data
28
+ - Grid lines are reference aids, not primary content — they should never compete with data
29
+
30
+ ## Tick marks
31
+
32
+ - Subtle or no ticks are preferred in modern chart design
33
+ - Use consistent intervals (don't skip values)
34
+ - Avoid excessive tick density — 5-7 ticks on a continuous axis is usually sufficient
35
+
36
+ ## Number formatting
37
+
38
+ - Use abbreviated formats: **20k, 20m, 20b** (not "in millions")
39
+ - Remove trailing zeros: **27%** not **27.0%**
40
+ - Use thousands separators: **1,000** not **1000**
41
+ - Repeat units on axis labels: **$20k** on each tick, not just "in thousands of dollars"
42
+
43
+ ## Logarithmic scales
44
+
45
+ - Use for data spanning multiple orders of magnitude
46
+ - Display relative changes and ratios
47
+ - Add horizontal reference lines at meaningful values
48
+ - Arrange symmetrically around the no-change point
49
+ - Use ratio notation (1/4, 1/2, 1, 2, 4) rather than decimal notation
50
+ - Label clearly — many audiences are unfamiliar with log scales
51
+
52
+ ## Aspect ratio
53
+
54
+ - Default to roughly **4:3** or **16:9** for standard charts
55
+ - Use **1:1** (square) when both axes share the same unit or meaning (observed vs. predicted, before vs. after)
56
+ - Aspect ratio dramatically affects perceived slope and trend interpretation
57
+
58
+ ::: tip
59
+ A trend that looks alarming at 3:1 can look flat at 3:4. When showing rate of change, pick an aspect ratio that reflects the underlying rate honestly — neither flattened nor exaggerated.
60
+ :::
61
+
62
+ ## How Blueprint Chart applies axes
63
+
64
+ Blueprint Chart's `AxisOptions` exposes scale type (linear / log), tick count, tick format, and baseline behavior. D3 scales drive the tick layout, and a shared number formatter is used by the axis, tooltip, and direct labels so the same value is rendered identically wherever it appears.
65
+
66
+ See the [API reference](/reference/api/) for the public options that toggle grid lines, tick density, and baseline zero.
67
+
68
+ ## Worked example: number format on the axis
69
+
70
+ ```bpc
71
+ chart line {
72
+ title = "Bitcoin surged past $90,000 in 2024"
73
+ description = "USD, year-end closing price"
74
+ source = "CoinGecko"
75
+ colors = "#f7931a"
76
+ verticalNumberFormat = ",.0f"
77
+ lineSymbols = true
78
+
79
+ data {
80
+ "2016" = 963
81
+ "2020" = 28949
82
+ "2021" = 46306
83
+ "2024" = 93429
84
+ }
85
+ }
86
+ ```
87
+
88
+ ::: info From `packages/lib/src/samples/bitcoin-price.bpc`
89
+ `verticalNumberFormat = ",.0f"` uses a D3 format string to add thousands separators and drop decimals — so the axis shows `93,429` instead of `93429.00`. The same formatter feeds the tooltip and any direct value labels, so identical values render identically in every slot.
90
+ :::
91
+
92
+ ## Worked example: gridlines that whisper
93
+
94
+ ```bpc
95
+ chart line {
96
+ title = "2024 was the hottest year on record"
97
+ colors = "#e15759"
98
+ showVerticalAxis = false
99
+ showVerticalTicks = false
100
+ verticalGridStyle = "dashed"
101
+ showHorizontalAxis = true
102
+ showHorizontalTicks = false
103
+ horizontalGridStyle = "none"
104
+ }
105
+ ```
106
+
107
+ ::: info From `packages/lib/src/samples/temperature-anomaly.bpc`
108
+ The vertical axis line and ticks are off; only dashed horizontal gridlines remain as reference. The horizontal axis stays visible but loses its ticks. Net result: gridlines whisper, the line speaks.
109
+ :::
110
+
111
+ ## See also
112
+
113
+ - [Labels & Legends](/handbook/labels)
114
+ - [Anti-Patterns](/handbook/anti-patterns)
115
+ - [Design Principles](/handbook/design-principles)
116
+ - [Frame Elements](/handbook/frame-elements)