@pixerate/editor 0.223.0 → 0.223.2
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/dist/agent/index.cjs +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/{chunk-SVHXD2VH.js → chunk-H73MSHYZ.js} +5 -1
- package/dist/{chunk-BDT2IYXK.cjs → chunk-VXLYEYP4.cjs} +6 -2
- package/dist/tools/index.cjs +2 -2
- package/dist/tools/index.js +1 -1
- package/dist/tools/skill-evals.d.cts +6 -1
- package/dist/tools/skill-evals.d.ts +6 -1
- package/package.json +1 -1
- package/skills/README.md +6 -1
- package/skills/pixerate-chart/SKILL.md +8 -0
- package/skills/pixerate-chart-annotate/SKILL.md +96 -0
- package/skills/pixerate-chart-annotate/evals/highlight-the-point.json +78 -0
- package/skills/pixerate-chart-annotate/evals/source-and-units.json +76 -0
- package/skills/pixerate-chart-annotate/evals/target-line.json +85 -0
- package/skills/pixerate-chart-choose-and-build/SKILL.md +100 -0
- package/skills/pixerate-chart-choose-and-build/evals/colour-blind-safe.json +113 -0
- package/skills/pixerate-chart-choose-and-build/evals/honest-baseline.json +81 -0
- package/skills/pixerate-chart-choose-and-build/evals/trend-over-time.json +175 -0
- package/skills/pixerate-spreadsheet/SKILL.md +2 -0
- package/skills/pixerate-spreadsheet-analysis/SKILL.md +97 -0
- package/skills/pixerate-spreadsheet-analysis/evals/count-and-average.json +148 -0
- package/skills/pixerate-spreadsheet-analysis/evals/month-over-month.json +128 -0
- package/skills/pixerate-spreadsheet-analysis/evals/summary-by-region.json +178 -0
- package/skills/pixerate-spreadsheet-financial-model/SKILL.md +98 -0
- package/skills/pixerate-spreadsheet-financial-model/evals/find-hardcoded.json +113 -0
- package/skills/pixerate-spreadsheet-financial-model/evals/projection-with-inputs.json +118 -0
- package/skills/pixerate-spreadsheet-financial-model/evals/scenarios.json +136 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-chart-choose-and-build
|
|
3
|
+
description: The chart building workflow in the Pixerate chart editor - starting from the question the chart answers, choosing the chart type for it (change over time, comparison, part of a whole, distribution, relationship, flow, geography), loading clean data in order, honest axes (bars from zero, log only for orders of magnitude), units and number formats, colours that colour-blind readers can tell apart, and checking before handing it over. Use when asked to make, build, create, choose, recommend or fix a chart or graph, visualise or plot data, pick the right chart, or make a chart clearer, more honest or accessible, or when recommend_chart, set_chart_data, update_chart or check_chart_colors are available. Load with pixerate-chart, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-chart
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Choosing and building a chart
|
|
10
|
+
|
|
11
|
+
A chart answers one question. Name the question first ("how did revenue change over the
|
|
12
|
+
year?", "which region sells most?"), and the type, the order of the data, the axes and the
|
|
13
|
+
title follow from it. Build in few calls: data in one, style in one, then check the warnings,
|
|
14
|
+
the colours and the numbers before anyone sees it.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-chart` has the full tool reference; for titles, highlights,
|
|
17
|
+
reference lines and notes that make the point, see `pixerate-chart-annotate`.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- The type fits the question (see the decision table).
|
|
22
|
+
- The data is in a meaningful order: time in calendar order, categories sorted by value unless
|
|
23
|
+
they have a natural order.
|
|
24
|
+
- Axes are honest: bars and areas start at zero; a log scale only when values span orders of
|
|
25
|
+
magnitude, and labelled as such; a second axis only for a second unit.
|
|
26
|
+
- Units are stated (axis title or number `format`); the title says what the chart shows.
|
|
27
|
+
- Colours pass `check_chart_colors` (`ok: true`) and there are at most about seven series
|
|
28
|
+
colours.
|
|
29
|
+
- `get_chart` `summary.warnings` and `issues` are empty.
|
|
30
|
+
|
|
31
|
+
## Inputs to confirm
|
|
32
|
+
|
|
33
|
+
- **The question** the chart must answer, and for whom (a report, a slide, a dashboard).
|
|
34
|
+
- **The data**: where it is (pasted, CSV, a spreadsheet, an Office file) and its units.
|
|
35
|
+
- **House style** if the host has one (`check_chart_style`).
|
|
36
|
+
|
|
37
|
+
## Working method
|
|
38
|
+
|
|
39
|
+
1. **Read.** `get_chart` (the spec, the data table, warnings); `list_file_charts` when the
|
|
40
|
+
data is in an open Office file.
|
|
41
|
+
2. **Name the question and choose the type.** `recommend_chart` suggests types for the data;
|
|
42
|
+
check its suggestion against the question (see the table).
|
|
43
|
+
**Check:** you can say the question in one sentence and why this type answers it.
|
|
44
|
+
3. **Load clean data in one call.** `set_chart_data` with categories in the right order and one
|
|
45
|
+
series per measure (or `import_chart_csv`); numbers as numbers, gaps as `null`.
|
|
46
|
+
**Check:** `get_chart` `spec.categories` and each series' `values` line up as intended.
|
|
47
|
+
4. **Style in one call.** `update_chart` with `type`, `title`, axis `title` and `format`,
|
|
48
|
+
`legend`, `stacking`, `orientation`, `dataLabels`. Bars from zero (`yAxis.min` null or 0).
|
|
49
|
+
**Check:** `get_chart` spec; `summary.description` reads as the chart you meant.
|
|
50
|
+
5. **Colours.** `check_chart_colors`; fix failing pairs with `update_chart_series` `color` (a
|
|
51
|
+
palette such as `#4269d0` / `#efb118` separates for most colour vision), or
|
|
52
|
+
`apply_chart_preset` for a tested palette.
|
|
53
|
+
**Check:** `check_chart_colors` `ok: true`.
|
|
54
|
+
6. **Look.** `render_chart` once after the batch; fix anything that does not read.
|
|
55
|
+
|
|
56
|
+
## Decision table
|
|
57
|
+
|
|
58
|
+
| Question | Type |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| How did it change over time? | `line` (one or a few series), `area` for totals, columns for few periods |
|
|
61
|
+
| Which is biggest? Compare categories | `bar`, horizontal for long labels, sorted by value |
|
|
62
|
+
| Part of a whole (few parts) | `pie` or `donut` (at most five slices), or a stacked bar |
|
|
63
|
+
| Part of a whole, nested | `treemap`, `sunburst` (`set_chart_tree`) |
|
|
64
|
+
| How are values distributed? | `histogram`, `box` |
|
|
65
|
+
| Do two measures relate? | `scatter`, `bubble` for a third measure |
|
|
66
|
+
| Before and after per category | `slope` |
|
|
67
|
+
| Contributions to a total | `waterfall` |
|
|
68
|
+
| Flows between stages | `sankey` (`set_chart_links`), `funnel` for one path |
|
|
69
|
+
| Survey answers | `likert` |
|
|
70
|
+
| By region on a map | `choropleth` |
|
|
71
|
+
|
|
72
|
+
## Recipes
|
|
73
|
+
|
|
74
|
+
**Trend over time.** `set_chart_data` with categories in calendar order → `update_chart`
|
|
75
|
+
`{ type: "line", title, yAxis: { title: "Revenue (USD thousands)" } }` → `get_chart`.
|
|
76
|
+
|
|
77
|
+
**Colour-blind fix.** `check_chart_colors` → `update_chart_series` `color` on the clashing series
|
|
78
|
+
→ `check_chart_colors` again.
|
|
79
|
+
|
|
80
|
+
**Honest bars.** `update_chart` `{ yAxis: { min: 0 } }`; when small differences matter, show the
|
|
81
|
+
differences themselves (a bar of the change) or a dot plot rather than a cut axis.
|
|
82
|
+
|
|
83
|
+
## Pitfalls
|
|
84
|
+
|
|
85
|
+
- **Truncated bar axes** exaggerate differences; bars start at zero.
|
|
86
|
+
- **Pie charts with many or similar slices** cannot be read; use a sorted bar.
|
|
87
|
+
- **Red and green** as the only distinction fail for the most common colour-vision deficiency.
|
|
88
|
+
- **Unsorted categories** without a natural order hide the ranking.
|
|
89
|
+
- **Mixed units on one axis**, or a second axis for the same unit, mislead.
|
|
90
|
+
- **Missing units** leave the reader guessing; put them in the axis title or format.
|
|
91
|
+
|
|
92
|
+
## Tools used
|
|
93
|
+
|
|
94
|
+
- `get_chart`, `render_chart`: the spec, data table, warnings, and a picture
|
|
95
|
+
- `recommend_chart`: types that suit the data
|
|
96
|
+
- `set_chart_data`, `import_chart_csv`, `transpose_chart`: load the data in order
|
|
97
|
+
- `update_chart`, `update_chart_series`, `apply_chart_preset`: type, titles, axes, formats and colours
|
|
98
|
+
- `check_chart_colors`, `check_chart_style`: colour-blind and house-style checks
|
|
99
|
+
- `list_file_charts`, `load_file_chart`: data from open Office files
|
|
100
|
+
- `undo_chart`: take back a step
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Some of our readers are colour-blind and can't tell the two years apart in this chart. Fix the colours without changing the data.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "chart",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_chart_data",
|
|
8
|
+
"args": {
|
|
9
|
+
"categories": [
|
|
10
|
+
"North",
|
|
11
|
+
"South",
|
|
12
|
+
"East",
|
|
13
|
+
"West"
|
|
14
|
+
],
|
|
15
|
+
"series": [
|
|
16
|
+
{
|
|
17
|
+
"name": "2025",
|
|
18
|
+
"values": [
|
|
19
|
+
12,
|
|
20
|
+
15,
|
|
21
|
+
9,
|
|
22
|
+
11
|
|
23
|
+
],
|
|
24
|
+
"color": "#d62728"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"name": "2026",
|
|
28
|
+
"values": [
|
|
29
|
+
14,
|
|
30
|
+
13,
|
|
31
|
+
12,
|
|
32
|
+
15
|
|
33
|
+
],
|
|
34
|
+
"color": "#2ca02c"
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"tool": "update_chart",
|
|
41
|
+
"args": {
|
|
42
|
+
"type": "bar",
|
|
43
|
+
"title": "Sales by region"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"checks": [
|
|
49
|
+
{
|
|
50
|
+
"why": "the colours pass the colour-blind check",
|
|
51
|
+
"tool": "check_chart_colors",
|
|
52
|
+
"expect": {
|
|
53
|
+
"ok": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"why": "the data is unchanged",
|
|
58
|
+
"tool": "get_chart",
|
|
59
|
+
"expect": {
|
|
60
|
+
"spec": {
|
|
61
|
+
"categories": [
|
|
62
|
+
"North",
|
|
63
|
+
"South",
|
|
64
|
+
"East",
|
|
65
|
+
"West"
|
|
66
|
+
],
|
|
67
|
+
"series": [
|
|
68
|
+
{
|
|
69
|
+
"name": "2025",
|
|
70
|
+
"values": [
|
|
71
|
+
12,
|
|
72
|
+
15,
|
|
73
|
+
9,
|
|
74
|
+
11
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "2026",
|
|
79
|
+
"values": [
|
|
80
|
+
14,
|
|
81
|
+
13,
|
|
82
|
+
12,
|
|
83
|
+
15
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
"solution": [
|
|
92
|
+
{
|
|
93
|
+
"tool": "check_chart_colors"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"tool": "update_chart_series",
|
|
97
|
+
"args": {
|
|
98
|
+
"series": "2025",
|
|
99
|
+
"color": "#4269d0"
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"tool": "update_chart_series",
|
|
104
|
+
"args": {
|
|
105
|
+
"series": "2026",
|
|
106
|
+
"color": "#efb118"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"tool": "check_chart_colors"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "This bar chart makes the differences between teams look huge, but they're small. Make it honest.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "chart",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_chart_data",
|
|
8
|
+
"args": {
|
|
9
|
+
"categories": [
|
|
10
|
+
"Team A",
|
|
11
|
+
"Team B",
|
|
12
|
+
"Team C",
|
|
13
|
+
"Team D"
|
|
14
|
+
],
|
|
15
|
+
"series": [
|
|
16
|
+
{
|
|
17
|
+
"name": "Satisfaction (%)",
|
|
18
|
+
"values": [
|
|
19
|
+
92,
|
|
20
|
+
95,
|
|
21
|
+
94,
|
|
22
|
+
97
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"tool": "update_chart",
|
|
30
|
+
"args": {
|
|
31
|
+
"type": "bar",
|
|
32
|
+
"title": "Satisfaction by team",
|
|
33
|
+
"yAxis": {
|
|
34
|
+
"min": 90,
|
|
35
|
+
"max": 98
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"checks": [
|
|
42
|
+
{
|
|
43
|
+
"why": "bars start at zero (or the chart is no longer bars)",
|
|
44
|
+
"tool": "get_chart",
|
|
45
|
+
"expect": {
|
|
46
|
+
"spec": {
|
|
47
|
+
"$expr": "v.type !== 'bar' || v.yAxis.min === null || v.yAxis.min === 0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"why": "the data is unchanged",
|
|
53
|
+
"tool": "get_chart",
|
|
54
|
+
"expect": {
|
|
55
|
+
"spec": {
|
|
56
|
+
"series": [
|
|
57
|
+
{
|
|
58
|
+
"values": [
|
|
59
|
+
92,
|
|
60
|
+
95,
|
|
61
|
+
94,
|
|
62
|
+
97
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"solution": [
|
|
71
|
+
{
|
|
72
|
+
"tool": "update_chart",
|
|
73
|
+
"args": {
|
|
74
|
+
"yAxis": {
|
|
75
|
+
"min": 0,
|
|
76
|
+
"max": 100
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "This is our 2026 monthly revenue in thousands of US dollars, pasted in a muddle. Make a chart that shows how revenue changed over the year.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "chart",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_chart_data",
|
|
8
|
+
"args": {
|
|
9
|
+
"categories": [
|
|
10
|
+
"Mar",
|
|
11
|
+
"Jan",
|
|
12
|
+
"Feb",
|
|
13
|
+
"Jun",
|
|
14
|
+
"Apr",
|
|
15
|
+
"May",
|
|
16
|
+
"Sep",
|
|
17
|
+
"Jul",
|
|
18
|
+
"Aug",
|
|
19
|
+
"Dec",
|
|
20
|
+
"Oct",
|
|
21
|
+
"Nov"
|
|
22
|
+
],
|
|
23
|
+
"series": [
|
|
24
|
+
{
|
|
25
|
+
"name": "Revenue",
|
|
26
|
+
"values": [
|
|
27
|
+
51,
|
|
28
|
+
42,
|
|
29
|
+
45,
|
|
30
|
+
61,
|
|
31
|
+
48,
|
|
32
|
+
55,
|
|
33
|
+
70,
|
|
34
|
+
58,
|
|
35
|
+
64,
|
|
36
|
+
82,
|
|
37
|
+
68,
|
|
38
|
+
75
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"tool": "update_chart",
|
|
46
|
+
"args": {
|
|
47
|
+
"type": "pie"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"checks": [
|
|
53
|
+
{
|
|
54
|
+
"why": "a line or area chart for change over time",
|
|
55
|
+
"tool": "get_chart",
|
|
56
|
+
"expect": {
|
|
57
|
+
"spec": {
|
|
58
|
+
"type": {
|
|
59
|
+
"$in": [
|
|
60
|
+
"line",
|
|
61
|
+
"area"
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"why": "months in calendar order, with their own values",
|
|
69
|
+
"tool": "get_chart",
|
|
70
|
+
"expect": {
|
|
71
|
+
"spec": {
|
|
72
|
+
"categories": [
|
|
73
|
+
"Jan",
|
|
74
|
+
"Feb",
|
|
75
|
+
"Mar",
|
|
76
|
+
"Apr",
|
|
77
|
+
"May",
|
|
78
|
+
"Jun",
|
|
79
|
+
"Jul",
|
|
80
|
+
"Aug",
|
|
81
|
+
"Sep",
|
|
82
|
+
"Oct",
|
|
83
|
+
"Nov",
|
|
84
|
+
"Dec"
|
|
85
|
+
],
|
|
86
|
+
"series": [
|
|
87
|
+
{
|
|
88
|
+
"values": [
|
|
89
|
+
42,
|
|
90
|
+
45,
|
|
91
|
+
51,
|
|
92
|
+
48,
|
|
93
|
+
55,
|
|
94
|
+
61,
|
|
95
|
+
58,
|
|
96
|
+
64,
|
|
97
|
+
70,
|
|
98
|
+
68,
|
|
99
|
+
75,
|
|
100
|
+
82
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"why": "a title and a value axis that says the unit",
|
|
109
|
+
"tool": "get_chart",
|
|
110
|
+
"expect": {
|
|
111
|
+
"spec": {
|
|
112
|
+
"title": {
|
|
113
|
+
"$match": "\\S"
|
|
114
|
+
},
|
|
115
|
+
"yAxis": {
|
|
116
|
+
"$expr": "/usd|\\$|dollar/i.test(v.title) || v.format.style === 'currency' || /\\$/.test(v.format.prefix || '')"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
"solution": [
|
|
123
|
+
{
|
|
124
|
+
"tool": "get_chart"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"tool": "set_chart_data",
|
|
128
|
+
"args": {
|
|
129
|
+
"categories": [
|
|
130
|
+
"Jan",
|
|
131
|
+
"Feb",
|
|
132
|
+
"Mar",
|
|
133
|
+
"Apr",
|
|
134
|
+
"May",
|
|
135
|
+
"Jun",
|
|
136
|
+
"Jul",
|
|
137
|
+
"Aug",
|
|
138
|
+
"Sep",
|
|
139
|
+
"Oct",
|
|
140
|
+
"Nov",
|
|
141
|
+
"Dec"
|
|
142
|
+
],
|
|
143
|
+
"series": [
|
|
144
|
+
{
|
|
145
|
+
"name": "Revenue",
|
|
146
|
+
"values": [
|
|
147
|
+
42,
|
|
148
|
+
45,
|
|
149
|
+
51,
|
|
150
|
+
48,
|
|
151
|
+
55,
|
|
152
|
+
61,
|
|
153
|
+
58,
|
|
154
|
+
64,
|
|
155
|
+
70,
|
|
156
|
+
68,
|
|
157
|
+
75,
|
|
158
|
+
82
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"tool": "update_chart",
|
|
166
|
+
"args": {
|
|
167
|
+
"type": "line",
|
|
168
|
+
"title": "Revenue grew through 2026",
|
|
169
|
+
"yAxis": {
|
|
170
|
+
"title": "Revenue (USD thousands)"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
@@ -21,6 +21,8 @@ For these jobs, load the workflow skill too: it has the method, the checks betwe
|
|
|
21
21
|
the pitfalls, and uses the tools below.
|
|
22
22
|
|
|
23
23
|
- `pixerate-spreadsheet-clean-import`: tidying imported or pasted data: structure, headers, types, dates, duplicates.
|
|
24
|
+
- `pixerate-spreadsheet-analysis`: summaries, growth, shares and rankings as formulas that reconcile.
|
|
25
|
+
- `pixerate-spreadsheet-financial-model`: inputs, consistent calculation rows, scenarios and audits.
|
|
24
26
|
|
|
25
27
|
## Working method
|
|
26
28
|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-spreadsheet-analysis
|
|
3
|
+
description: The analysis workflow in a Pixerate spreadsheet - turning tidy data into answers with live formulas - summary tables by category (SUMIFS, COUNTIFS, AVERAGEIFS), distinct lists with UNIQUE, ranked and filtered views with SORT and FILTER, period totals and growth, shares of a total, checks that the summary reconciles with the data, and handing the result to a chart. Use when asked to summarise, total, count, average, group, pivot, rank, compare, break down or analyse data in a spreadsheet, work out growth or percentages, find the top items, or prepare numbers for a chart, or when get_range and set_range are available. Load with pixerate-spreadsheet, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-spreadsheet
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Analysing data in a spreadsheet
|
|
10
|
+
|
|
11
|
+
An analysis is a set of formulas that answer a question from the data and keep answering it
|
|
12
|
+
when the data changes. Start from tidy data (one header row, one record per row; clean it first
|
|
13
|
+
with `pixerate-spreadsheet-clean-import` if needed), put each summary in its own block beside or
|
|
14
|
+
below the data, and make every number a formula over the data, never a typed result.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-spreadsheet` has the full tool reference and the supported
|
|
17
|
+
functions; for the chart that shows the result, see `pixerate-chart-choose-and-build`.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- Every result is a formula over the data (`SUMIFS`, `COUNTIFS`, `AVERAGEIFS`, `FILTER`,
|
|
22
|
+
`UNIQUE`, `SORT`), with absolute references to the data range, so it updates and can be
|
|
23
|
+
checked.
|
|
24
|
+
- Summaries have a header row and one row per group; nothing is typed over a formula.
|
|
25
|
+
- The summary reconciles: group totals add up to the data's total.
|
|
26
|
+
- No formula errors (`get_range` `errors` empty); expected errors handled explicitly
|
|
27
|
+
(`IFERROR` around a division by a possible zero), and blanks where a value does not apply.
|
|
28
|
+
- The data itself is untouched.
|
|
29
|
+
|
|
30
|
+
## Inputs to confirm
|
|
31
|
+
|
|
32
|
+
- **The question** (totals by region, growth by month, top products) and the measure.
|
|
33
|
+
- **Where the result goes** (a cell such as G1, or below the data).
|
|
34
|
+
- **Groups:** a fixed list the user gives, or every distinct value in the data (`UNIQUE`).
|
|
35
|
+
|
|
36
|
+
## Working method
|
|
37
|
+
|
|
38
|
+
1. **Read the data.** `get_range` the header and a sample; note the data range, which column is
|
|
39
|
+
the group and which the measure, and whether it is tidy.
|
|
40
|
+
**Check:** one header row, one record per row, numbers as numbers.
|
|
41
|
+
2. **Lay out the summary** in an empty area: a header row, then one row per group. List groups
|
|
42
|
+
yourself when there are few and fixed, or `=UNIQUE(B2:B500)` for every value (leave room for
|
|
43
|
+
it to spill).
|
|
44
|
+
3. **Write the formulas in one block.** `set_range` with the header and a formula per row, each
|
|
45
|
+
with absolute data references and a relative group cell: `=SUMIFS($D$2:$D$500,$B$2:$B$500,G2)`.
|
|
46
|
+
**Check:** the returned `errors` is empty.
|
|
47
|
+
4. **Reconcile.** Add a total row (`=SUM(H2:H5)`) and compare it with `=SUM($D$2:$D$500)`; for
|
|
48
|
+
counts, with `=COUNTA` of the key column.
|
|
49
|
+
**Check:** they match; if not, a group is missing or a value is text.
|
|
50
|
+
5. **Derived measures**: growth `=B3/B2-1` (blank for the first period), share `=H2/SUM($H$2:$H$5)`,
|
|
51
|
+
rank `=RANK(H2,$H$2:$H$5)`, ranked lists `=SORT(G2:H5,2,-1)`.
|
|
52
|
+
**Check:** `get_range` values match a hand calculation for one row.
|
|
53
|
+
6. **Hand over.** Tell the user where the summary is and what each column means; to chart it,
|
|
54
|
+
pass the summary block (categories and values) to the chart editor's `set_chart_data`.
|
|
55
|
+
|
|
56
|
+
## Decision table
|
|
57
|
+
|
|
58
|
+
| Question | Formula |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| Total per group | `SUMIFS(measure, group_range, group)` |
|
|
61
|
+
| How many per group | `COUNTIFS(group_range, group)` |
|
|
62
|
+
| Average per group | `AVERAGEIFS(measure, group_range, group)` |
|
|
63
|
+
| Two conditions (region and month) | `SUMIFS` with two criteria pairs |
|
|
64
|
+
| Every distinct group | `UNIQUE(group_range)`, spilled |
|
|
65
|
+
| Rows that meet a condition | `FILTER(data, condition)` |
|
|
66
|
+
| Top items | `SORT` (or `SORTBY`) the summary by its total, descending |
|
|
67
|
+
| Change from the previous period | `=this/previous-1`, first period blank |
|
|
68
|
+
| Share of total | `=value/SUM($total_range)` |
|
|
69
|
+
|
|
70
|
+
## Recipes
|
|
71
|
+
|
|
72
|
+
**Totals by region at G1.** `set_range` from G1 with `[["Region", "Total"], ["North",
|
|
73
|
+
"=SUMIFS($D$2:$D$11,$B$2:$B$11,G2)"], ...]` (each row's formula pointing at its own G cell).
|
|
74
|
+
|
|
75
|
+
**Month-over-month growth in C.** `set_range` from C1: `[["Growth"], [null], ["=B3/B2-1"],
|
|
76
|
+
["=B4/B3-1"], ...]`.
|
|
77
|
+
|
|
78
|
+
**Orders and average per product.** Columns `=COUNTIFS($C$2:$C$11,G2)` and
|
|
79
|
+
`=AVERAGEIFS($D$2:$D$11,$C$2:$C$11,G2)`.
|
|
80
|
+
|
|
81
|
+
## Pitfalls
|
|
82
|
+
|
|
83
|
+
- **Typed results.** A number typed into a summary does not update; always a formula.
|
|
84
|
+
- **Relative data references.** `D2:D11` shifts when you write the formula down; use `$D$2:$D$11`.
|
|
85
|
+
- **Text numbers** in the measure column are skipped by `SUMIFS`; clean the data first.
|
|
86
|
+
- **Spills blocked**: `UNIQUE`, `FILTER` and `SORT` need empty cells below and to the right.
|
|
87
|
+
- **Totals inside the data range** double-count; keep summaries outside it.
|
|
88
|
+
- **0 for "no previous period"** misleads averages; leave it blank.
|
|
89
|
+
- **`set_range` writes formulas as given**: write each row's own references.
|
|
90
|
+
|
|
91
|
+
## Tools used
|
|
92
|
+
|
|
93
|
+
- `get_range`: read the data and check every result and error
|
|
94
|
+
- `set_range`: write summary blocks with headers and formulas, one undo step
|
|
95
|
+
- `set_cell`: fix one formula
|
|
96
|
+
- `insert_columns`, `insert_rows`: make room for a summary
|
|
97
|
+
- `undo_spreadsheet`: take back a step
|