@bezda/rhp-mcp 0.0.0-stage → 0.1.1
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.
- package/LICENSE +21 -0
- package/README.md +222 -2
- package/bin/rhp-mcp.js +129 -0
- package/package.json +62 -4
- package/skill/SKILL.md +450 -0
- package/skill/recipes/area.html +156 -0
- package/skill/recipes/bar.html +145 -0
- package/skill/recipes/box-plot.html +164 -0
- package/skill/recipes/bubble.html +188 -0
- package/skill/recipes/bullet.html +138 -0
- package/skill/recipes/candlestick.html +179 -0
- package/skill/recipes/column.html +138 -0
- package/skill/recipes/dial.html +349 -0
- package/skill/recipes/diverging-bars.html +150 -0
- package/skill/recipes/donut.html +231 -0
- package/skill/recipes/dumbbell.html +137 -0
- package/skill/recipes/gantt.html +196 -0
- package/skill/recipes/grouped-bars.html +142 -0
- package/skill/recipes/heatmap.html +183 -0
- package/skill/recipes/histogram.html +199 -0
- package/skill/recipes/line.html +170 -0
- package/skill/recipes/live.html +255 -0
- package/skill/recipes/log-line.html +493 -0
- package/skill/recipes/lollipop.html +152 -0
- package/skill/recipes/multi-line.html +228 -0
- package/skill/recipes/pyramid.html +162 -0
- package/skill/recipes/race.html +278 -0
- package/skill/recipes/radial-bars.html +157 -0
- package/skill/recipes/scatter.html +199 -0
- package/skill/recipes/silhouettes.html +352 -0
- package/skill/recipes/slope.html +199 -0
- package/skill/recipes/sparklines.html +175 -0
- package/skill/recipes/stacked-100.html +158 -0
- package/skill/recipes/stacked-bars.html +150 -0
- package/skill/recipes/strip.html +221 -0
- package/skill/recipes/unit-stack.html +276 -0
- package/skill/recipes/violin.html +169 -0
- package/skill/recipes/waffle.html +165 -0
- package/skill/recipes/waterfall.html +127 -0
- package/skill/references/api.md +1684 -0
- package/skill/references/design.md +740 -0
- package/skill/references/environments.md +1577 -0
- package/skill/references/forms.md +197 -0
- package/skill/references/interaction.md +794 -0
- package/skill/references/looks.md +267 -0
- package/skill/references/pitfalls.md +202 -0
- package/src/check/README.md +176 -0
- package/src/check/browser.js +92 -0
- package/src/check/build.js +439 -0
- package/src/check/colors.js +324 -0
- package/src/check/findings.js +247 -0
- package/src/check/index.js +508 -0
- package/src/check/inpage.js +1332 -0
- package/src/check/interact.js +266 -0
- package/src/check/png.js +98 -0
- package/src/check/report.js +106 -0
- package/src/check/source.js +387 -0
- package/src/check/sourcemap.js +75 -0
- package/src/guard/note.js +30 -0
- package/src/guard/render.js +17 -0
- package/src/guard/rhp.js +612 -0
- package/src/guard/rules.js +125 -0
- package/src/server.js +266 -0
- package/src/skill.js +140 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# Choosing the form: data, story, slat and recipe
|
|
2
|
+
|
|
3
|
+
Use this file in step 3 of the workflow, after the brief.
|
|
4
|
+
It goes from the subject and what the reader should see, to the form, to the slat that draws it, to the recipe that has the technique.
|
|
5
|
+
When the user named a form ("a donut", "a gantt"), use it, and start at the recipe catalog below.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- Start from the subject's own form
|
|
10
|
+
- Start from the reader's question
|
|
11
|
+
- The compositions rhp charts are made of
|
|
12
|
+
- The recipe catalog
|
|
13
|
+
- Orientation, size and phones
|
|
14
|
+
- Combining recipes
|
|
15
|
+
- What rhp does not draw, and the closest answer
|
|
16
|
+
|
|
17
|
+
## Start from the subject's own form
|
|
18
|
+
|
|
19
|
+
Before the data's shape, look at the subject's.
|
|
20
|
+
A reader already knows what it looks like, and a chart that takes that form is recognized before a word is read.
|
|
21
|
+
rhp draws all of these; the recipe named has the technique, not the design.
|
|
22
|
+
|
|
23
|
+
| The subject has | The form that carries it | Technique |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| a cycle that turns (hours of a day, days of a week, months, seasons, a rotation) | a ring or a dial with the cycle around it, or a calendar grid | `dial` (arcs around a 24-hour face), `donut` (wedges from shares), `radial-bars` (arcs), `heatmap` (a grid of Cells) |
|
|
26
|
+
| things known by their outline (buildings, mountains, animals, ships, bottles) | each one drawn in its own outline, to scale, on one ground line | `silhouettes` (a `shape()` per row on a vertical Bar) |
|
|
27
|
+
| units a reader can count (people, seats, days, coins, floors) | one small mark per unit, or a bar cut into units | `waffle` (Cells, a picture in each), `unit-stack` (a Bar cut by a mask) |
|
|
28
|
+
| something that fills (rain, fuel, a battery, a budget, a quota) | a vessel up to the top of the scale, with its content inside | `column` (a tube and its water), `bullet` (bands and a target) |
|
|
29
|
+
| a level things rise above or sink below (sea level, ground, zero, par, a freezing point) | bars or lines hanging from, or standing on, that one line | `diverging-bars`; in a vertical chart, values below the level are negative and hang from it |
|
|
30
|
+
| a route or a sequence in space (stops, stages, a course, a river) | one line with its stations in order | `stacked-100` (its key is a metro line), `gantt`, `slope` |
|
|
31
|
+
| a document the reader knows (a receipt, a ledger, a timetable, a scoreboard, a league table, a menu) | the chart laid out as that document, its lines the slats | `lollipop`, `waterfall`, `sparklines`, `live` |
|
|
32
|
+
| a place (states, districts, seats in a hall, a pitch, a shelf) | a grid of tiles that echoes the place | `heatmap`'s composition (a Plot of rows, each a Plot of Cells) |
|
|
33
|
+
| an instrument that measures it (a thermometer, a gauge, a ruler, a clock, a scale) | the instrument's own scale and pointer | a `Scale` drawn your own way, a Tick as the pointer, `radial-bars` |
|
|
34
|
+
|
|
35
|
+
- The native form is the hero, and the numbers still have to be read: print each value on or beside its mark, since a ring, an outline or a tile is read less exactly than a bar on a shared baseline.
|
|
36
|
+
- When an exact comparison is the whole point, keep bars from one baseline and let the subject show in how the marks are drawn (design.md section 2).
|
|
37
|
+
- When the subject has no form of its own (abstract values, quarters of a year, A against B), the form comes from the reader's question below, and the idea from what the numbers do: the gap, the turn, the outlier.
|
|
38
|
+
- A ring of the parts of a day reads as a clock: a part drawn from midnight to 9 is read as "from midnight to 9".
|
|
39
|
+
Put each part where it happens in the day, or keep the ring in order of size and leave the hour numerals off it.
|
|
40
|
+
- Never bend the data to fit the form: a ring is for parts of a cycle or of a whole, an outline is scaled in one direction only, and units are all one size.
|
|
41
|
+
|
|
42
|
+
## Start from the reader's question
|
|
43
|
+
|
|
44
|
+
Write the one question the chart answers before you pick a form.
|
|
45
|
+
The headline will be its answer.
|
|
46
|
+
|
|
47
|
+
| The reader wants to... | Data | Form | Recipe |
|
|
48
|
+
|---|---|---|---|
|
|
49
|
+
| see which is biggest, in order | one value per item | ranked horizontal bars | `bar` |
|
|
50
|
+
| compare a few periods or categories | one value per period | columns | `column` |
|
|
51
|
+
| see a ranking with a reference value | one value per item and a reference | lollipop with a baseline | `lollipop` |
|
|
52
|
+
| compare two to four values per item | a few values per item, same unit | grouped bars | `grouped-bars` |
|
|
53
|
+
| see totals and what they are made of | parts per item that add up | stacked bars | `stacked-bars` |
|
|
54
|
+
| compare how each whole splits | parts per item, as shares | 100% stacked bars | `stacked-100` |
|
|
55
|
+
| see two sides of zero (agree and disagree, gain and loss) | values above and below zero | diverging bars | `diverging-bars` |
|
|
56
|
+
| follow how one amount becomes another | a start, changes, an end | waterfall | `waterfall` |
|
|
57
|
+
| see a few parts of one whole | two to six parts | donut | `donut` |
|
|
58
|
+
| count out of 100 people or units | counts or shares of a population | waffle | `waffle` |
|
|
59
|
+
| see progress toward goals | a share of a target per goal | radial bars, or bullets | `radial-bars`, `bullet` |
|
|
60
|
+
| see actual against target | actual, target, quality bands | bullet | `bullet` |
|
|
61
|
+
| follow one measure over time | a value per date | line | `line` |
|
|
62
|
+
| follow a measure that grows by multiples, and its falls | a value per date, over a wide range | a line on a log scale | `log-line` |
|
|
63
|
+
| compare a few measures over time | a value per date per series | multi-line | `multi-line` |
|
|
64
|
+
| see a quantity's volume over time | a value per hour or day | area | `area` |
|
|
65
|
+
| see change between two dates per item | two values per item | slope | `slope` |
|
|
66
|
+
| see the gap between two values per item | two values per item | dumbbell | `dumbbell` |
|
|
67
|
+
| see many small trends at a glance | a short series per item | sparklines in slats | `sparklines` |
|
|
68
|
+
| watch a ranking reshuffle over time | one value per item per step | a bar chart race | `race` |
|
|
69
|
+
| follow values that keep arriving | a feed of readings per item | a live board | `live` |
|
|
70
|
+
| see how one measure is spread | many samples | histogram | `histogram` |
|
|
71
|
+
| compare spreads of a few groups, summarized | samples per group | box plot | `box-plot` |
|
|
72
|
+
| compare full distributions of a few groups | samples per group | violin | `violin` |
|
|
73
|
+
| see every value of a few groups | samples per group, tens per group | strip plot | `strip` |
|
|
74
|
+
| see how two measures relate | two values per item | scatter | `scatter` |
|
|
75
|
+
| see two measures and a size | three values per item | bubble | `bubble` |
|
|
76
|
+
| see a value over two categories | a grid of values (day by hour) | heatmap | `heatmap` |
|
|
77
|
+
| see two groups across ordered bands | two values per band | pyramid | `pyramid` |
|
|
78
|
+
| see things known by their shape at their size | one value per item, each item with an outline | silhouettes to scale | `silhouettes` |
|
|
79
|
+
| see how a day or another cycle splits | parts that add up to the cycle | a dial | `dial` |
|
|
80
|
+
| follow one part of a total over periods, and count it | parts per period that add up | unit stacks with the part at the foot | `unit-stack` |
|
|
81
|
+
| see a schedule and its progress | tasks with start, end, progress | gantt | `gantt` |
|
|
82
|
+
| follow prices with their range | open, high, low, close per day | candlestick | `candlestick` |
|
|
83
|
+
|
|
84
|
+
If two forms fit, prefer the one whose marks the reader compares by length from a shared baseline (bars, columns, lollipops): length is read most precisely.
|
|
85
|
+
Use a donut only for two to six parts with one or two of them the story; otherwise use stacked or ranked bars.
|
|
86
|
+
|
|
87
|
+
## The compositions rhp charts are made of
|
|
88
|
+
|
|
89
|
+
The slat compositions below use one or more Plots inside a Chart.
|
|
90
|
+
For bulk scatter points, an experimental [ManyDots collection](api.md#manydots-experimental-point-collection) can instead sit directly inside a Chart with `cross`, without a Plot or per-point slat.
|
|
91
|
+
These are the patterns the recipes use; recognizing them lets you build a chart no recipe has.
|
|
92
|
+
|
|
93
|
+
1. **One value per slat**: an edge Label for the name, a Bar from 0 (or `from`) to the value, a value Label at its end.
|
|
94
|
+
Recipes: `bar`, `column`, `lollipop` (a thin Bar and a Dot), `histogram`, `waterfall` (Bars from the running total before to the one after), `silhouettes` (a Bar wearing its row's `shape()`).
|
|
95
|
+
2. **Several values on one slat, same scale**: several blocks in the same slat, each at its own value.
|
|
96
|
+
Recipes: `dumbbell` (two Dots and the Bar between them), `bullet` (band Bars, the actual Bar, a target Tick), `box-plot` (Bars for whiskers and box, Ticks for the median), `candlestick` (a thin Bar for the wick, a wide one for the body), `gantt` (planned, done and late Bars), `pyramid` (a Bar to each side of zero), `unit-stack` (a Bar to the picked part and a Bar from it to the total, each cut into coins by a mask).
|
|
97
|
+
3. **Parts of each slat**: a Plot inside the slat, one inner slat per part.
|
|
98
|
+
An `overlap` inner Plot puts the parts in one band, which makes a stack (`stacked-bars`, `stacked-100`, with `stackUp()` and `shares()`); an inner Plot without `overlap` lays the parts side by side across the band (`grouped-bars`).
|
|
99
|
+
4. **A grid**: a Plot of Cells inside each slat, one Cell per column of the grid.
|
|
100
|
+
Recipes: `heatmap` (days by hours), `waffle` (ten slats of ten people).
|
|
101
|
+
5. **Points on two axes**: `cross={[min, max]}` on the Chart adds a second axis across the slats; an `overlap` Plot's slats then share the whole plot, and a Dot or Label takes `at` (along the scale) and `cross` (across it), a Line takes `[x, y]` points.
|
|
102
|
+
Recipes: `scatter`, `bubble` (Dot size from a value), `line`, `multi-line`, `area` (a filled Line), `slope` (a Line of two points per item).
|
|
103
|
+
`ManyDots` is an explicit alternative for bulk points with individual colors, sizes, shapes, classes, and styles; keep `Dot` for rich point content and Plot's automatic interaction features.
|
|
104
|
+
6. **Every value of a group in its band**: an `overlap` Plot of Dots inside each group's slat.
|
|
105
|
+
Recipe: `strip`.
|
|
106
|
+
7. **A distribution's outline**: an Area from `density()` points, `mirror` for violins.
|
|
107
|
+
Recipe: `violin`.
|
|
108
|
+
8. **Layers over the slats**: an overlay Plot drawn over the others with `style=${{ "pointer-events": "none" }}` and `room: {}` on its slat type: a crosshair, a today line, a baseline, outliers.
|
|
109
|
+
Recipes: `candlestick` and `multi-line` (crosshairs), `gantt` (today), `lollipop` (the baseline), `box-plot` (outliers).
|
|
110
|
+
9. **A scale drawn your own way**: a `Scale` in the Chart, a Plot of ticks with `d.at`, `d.next`, `d.first`, `d.last`.
|
|
111
|
+
Recipes: `gantt` (weeks), `line` and `multi-line` (decades), `scatter` and `bubble` (log scales), `area` (hours), `slope` (the two dates).
|
|
112
|
+
10. **Shapes drawn from Bars**: the slat's CSS gives a Bar a new box, and the Bar draws a wedge or an arc from its values.
|
|
113
|
+
Recipes: `donut` (an SVG wedge inside each Bar, from `stackUp()` of `shares()`), `radial-bars` (rings drawn in CSS from the Bar's `--rhp-hi`).
|
|
114
|
+
Start from these recipes; the CSS is the hard part.
|
|
115
|
+
|
|
116
|
+
Inside any slat, add ordinary elements where the story needs them: an icon or a flag in the name Label, a note beside the highlighted slat, a small image in a Place.
|
|
117
|
+
|
|
118
|
+
## The recipe catalog
|
|
119
|
+
|
|
120
|
+
Each recipe is a complete page in `recipes/<name>.html` with a designed poster, fixed data and one interaction.
|
|
121
|
+
The comment at the top of each says what to take (its technique) and what to leave (its design, made for its own subject).
|
|
122
|
+
The interaction listed is the recipe's; interaction.md has the others.
|
|
123
|
+
|
|
124
|
+
| Recipe | Shows | Composition | Interaction |
|
|
125
|
+
|---|---|---|---|
|
|
126
|
+
| `bar` | ranked categories, long names, the top one highlighted | 1 | readout on hover, focus and tap |
|
|
127
|
+
| `column` | values over twelve months, a season marked | 1, vertical | a scrub with a running total |
|
|
128
|
+
| `grouped-bars` | two values per category | 3 (side by side) | sort switch |
|
|
129
|
+
| `stacked-bars` | totals made of parts | 3 (stack) | a key that moves one part to the start and ranks by it |
|
|
130
|
+
| `stacked-100` | shares of each whole | 3 (stack of shares) | a key that lights one part in every bar |
|
|
131
|
+
| `diverging-bars` | survey answers either side of zero | 2 (Bars to both sides) | a switch between questions |
|
|
132
|
+
| `waterfall` | a profit bridge | 1 (Bars between running totals) | a switch between periods |
|
|
133
|
+
| `lollipop` | ranked prices against a reference | 1 + 8 | a switch between values and differences |
|
|
134
|
+
| `bullet` | actual against target with bands | 2 | sort by value or by share of target |
|
|
135
|
+
| `donut` | a few parts of one whole | 10 | the slice read out in place |
|
|
136
|
+
| `radial-bars` | progress on five goals | 10 | a day switch |
|
|
137
|
+
| `waffle` | 100 people by group | 4 | a picker that lights related units |
|
|
138
|
+
| `heatmap` | a value by weekday and hour | 4 | readout of a cell; turns on phones |
|
|
139
|
+
| `line` | one series over time | 5 + 9 | a callout that follows pointer, tap and arrow keys |
|
|
140
|
+
| `multi-line` | several series over time | 5 + 8 + 9 | a crosshair with every series' value |
|
|
141
|
+
| `area` | one quantity over a day | 5 + 9 | a switch between two days, the other kept as a thin line |
|
|
142
|
+
| `scatter` | two measures per item | 5 + 9 | readout of the nearest point |
|
|
143
|
+
| `bubble` | two measures and a size | 5 + 9 | readout of the bubble under the pointer |
|
|
144
|
+
| `slope` | change between two dates | 5 + 9 | the line nearest the pointer picked out |
|
|
145
|
+
| `dumbbell` | two values per item and the gap | 2 | re-sort by level or by change |
|
|
146
|
+
| `histogram` | one measure's spread | 1, vertical, `bins()` | readout of a bin and the share ahead of it |
|
|
147
|
+
| `box-plot` | spreads of groups, summarized | 2 + 8, `summary()` | readout of a group |
|
|
148
|
+
| `violin` | full distributions of groups | 7, `density()` | a switch that morphs the shapes |
|
|
149
|
+
| `strip` | every value of a few groups | 6 | readout of a dot |
|
|
150
|
+
| `pyramid` | two sides of a population by age | 2 | an age picked lights everyone that age or older |
|
|
151
|
+
| `silhouettes` | ten towers to scale, each in its own outline, on one street | 1, vertical, `shape()` per row | readout of the tower picked, its level carried to the tallest |
|
|
152
|
+
| `dial` | the parts of a day around a 24-hour dial | 10 + 9 | a hand that turns to the part picked, a readout in the hub |
|
|
153
|
+
| `log-line` | ten years of a price on a log scale with a line at each doubling, its falls shaded | 5 (the falls as one filled Line) + 8 + 9, log scale | a crosshair readout by pointer, tap, drag or keys |
|
|
154
|
+
| `unit-stack` | monthly spending as piles of coins, one part at the foot of every pile | 2 (the picked part and the rest), units by a mask | a picker of parts |
|
|
155
|
+
| `gantt` | tasks over weeks, progress, today | 2 + 8 + 9 | readout of a task and its dependencies |
|
|
156
|
+
| `candlestick` | daily open, high, low, close | 2 + 8 | a crosshair and price readout |
|
|
157
|
+
| `sparklines` | a table of trends, one per slat, each scaled to itself | 1 + a Line in each slat + 8 | a year scrubber (pointer, tap, drag; a keyboard slider) |
|
|
158
|
+
| `race` | a ranking that reshuffles step by step, played over time | 1, JS motion, the scale following the leader | play and pause, a year slider, a readout |
|
|
159
|
+
| `live` | values arriving from a feed, each slat with its last minute scrolling | 1 + a Line from one animated `now` | pause and resume, a readout |
|
|
160
|
+
|
|
161
|
+
Adapting a recipe:
|
|
162
|
+
|
|
163
|
+
- **More or fewer slats**: a horizontal chart grows with its slats (`thickness`); keep 18px or more per slat for a name, 28px or more for a name and a value. Over about 30 rows, show the top ones and say so in the dek, or switch to a form that summarizes (a histogram, a box plot).
|
|
164
|
+
- **Negative values**: give the scale a min below 0 (`nice(min, max)`), and put value Labels for negative bars on the other side (`side="before"`).
|
|
165
|
+
- **Long names**: room in px for the longest, or `max-width` with an ellipsis, or wrap; on phones consider the other orientation.
|
|
166
|
+
- **More series**: grouped bars stay readable to four series; stacks to five or six parts; lines to five or six series, with direct labels at the line ends. Beyond that, highlight one or two and mute the rest, or split into small multiples (a Plot inside each slat).
|
|
167
|
+
- **Other units**: change `format` and the value Labels with `Intl.NumberFormat`, and the units in the headline, dek or axis.
|
|
168
|
+
|
|
169
|
+
## Orientation, size and phones
|
|
170
|
+
|
|
171
|
+
- **Horizontal** (the default): rankings, long names, many items. Names sit in the start room, values at the bar ends.
|
|
172
|
+
- **Vertical**: time periods and short category names, up to about 24 columns on a desktop and 12 on a phone. Give it a `height` (240px by default is usually too short for a poster: 300 to 420px).
|
|
173
|
+
- **Two axes** (`cross`): time series, scatter and bubble charts. Give the Chart a `height` that suits the data's spread (260 to 420px).
|
|
174
|
+
- **Phones (390px wide)**: everything must still fit. Shorten or wrap names, drop a secondary label, use fewer ticks, or switch orientation with a `matchMedia` signal (the `heatmap` recipe turns its grid on phones; `column` keeps months short).
|
|
175
|
+
|
|
176
|
+
## Combining recipes
|
|
177
|
+
|
|
178
|
+
When the story needs a slat no recipe has, take each part from the recipe that has it.
|
|
179
|
+
|
|
180
|
+
- **A table of trends with a target or a rank**: `sparklines` plus a Tick for the target from `bullet`, or `order=${sortBy("latest", "desc")}` from `bar` (a Line in a slat without `cross` is scaled to its own slat; give `peak` to compare slats).
|
|
181
|
+
- **Ranked bars with a target**: `bar` plus the target Tick from `bullet`.
|
|
182
|
+
- **A ranking that changes over time** (a bar chart race): start from `race`, which moves by the JS version because its data changes without pause.
|
|
183
|
+
- **A tile grid map** (states or countries as cells laid out like a map): a Plot of rows, each slat a Plot of Cells (the `heatmap` composition), with empty cells where there is no state.
|
|
184
|
+
|
|
185
|
+
## What rhp does not draw, and the closest answer
|
|
186
|
+
|
|
187
|
+
Say plainly in your brief when a request is outside rhp, then build the closest rhp answer and say why in the handoff.
|
|
188
|
+
|
|
189
|
+
| Asked for | Closest rhp answer |
|
|
190
|
+
|---|---|
|
|
191
|
+
| a geographic map (choropleth) | a tile grid map (each region a Cell placed in a grid that echoes the map), or ranked bars of the regions |
|
|
192
|
+
| a network or a flow diagram (sankey) | stacked bars of what goes where, or a matrix heatmap of from-to pairs |
|
|
193
|
+
| a treemap or a sunburst | a waffle for shares, or stacked bars for parts of parts |
|
|
194
|
+
| a radar (spider) chart | a dot plot or grouped bars across the same axes |
|
|
195
|
+
| a 3D chart | the 2D form of the same data |
|
|
196
|
+
| a word cloud | ranked bars of the words |
|
|
197
|
+
| a free-form drawing or an image | Place blocks to position your own elements, or an image next to the chart |
|