dsh-office-kit 0.4.2 → 0.4.3
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/assets/skills/excel-live-control/SKILL.md +119 -152
- package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
- package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
- package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
- package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
- package/assets/skills/excel-live-control/references/office-automation.md +127 -153
- package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
- package/assets/skills/excel-live-control/style_guidelines.md +56 -64
- package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
- package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
- package/assets/skills/office-documents/SKILL.md +24 -60
- package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
- package/assets/skills/office-documents/ooxml/comments.md +8 -8
- package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
- package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
- package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
- package/assets/skills/office-documents/references/docx-structure.md +11 -13
- package/assets/skills/office-documents/references/template-elicitation.md +11 -13
- package/assets/skills/office-documents/references/writing-quality.md +20 -20
- package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
- package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
- package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
- package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
- package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
- package/assets/skills/office-documents/tasks/create_edit.md +14 -16
- package/assets/skills/office-documents/tasks/equations.md +17 -28
- package/assets/skills/office-documents/tasks/fields_update.md +14 -16
- package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
- package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
- package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
- package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
- package/assets/skills/office-documents/tasks/images_figures.md +15 -25
- package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
- package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
- package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
- package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
- package/assets/skills/office-documents/tasks/read_review.md +9 -20
- package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
- package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
- package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
- package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
- package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
- package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
- package/assets/skills/office-documents/tasks/verify_render.md +11 -23
- package/assets/skills/office-documents/tasks/watermarks_background.md +11 -15
- package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +6 -6
- package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
- package/assets/skills/office-pdf/SKILL.md +36 -51
- package/assets/skills/office-pdf/references/form-fields.md +20 -20
- package/assets/skills/office-pdf/references/geometry.md +10 -10
- package/assets/skills/office-pdf/references/layout-quality.md +13 -13
- package/assets/skills/office-pdf/references/limits.md +12 -56
- package/assets/skills/office-pdf/tasks/annotations.md +5 -5
- package/assets/skills/office-pdf/tasks/create.md +6 -9
- package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
- package/assets/skills/office-pdf/tasks/forms.md +15 -15
- package/assets/skills/office-pdf/tasks/read.md +9 -9
- package/assets/skills/office-pdf/tasks/redact.md +18 -18
- package/assets/skills/office-pdf/tasks/stamp.md +10 -10
- package/assets/skills/office-presentations/SKILL.md +71 -91
- package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
- package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
- package/assets/skills/office-presentations/recipes/README.md +24 -35
- package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
- package/assets/skills/office-presentations/recipes/connectors.md +11 -12
- package/assets/skills/office-presentations/recipes/images.md +11 -12
- package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
- package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
- package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
- package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
- package/assets/skills/office-presentations/recipes/tables.md +14 -14
- package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
- package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
- package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
- package/assets/skills/office-presentations/references/finalization.md +10 -12
- package/assets/skills/office-presentations/references/native-bullets.md +14 -18
- package/assets/skills/office-presentations/references/native-evidence.md +18 -32
- package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
- package/assets/skills/office-presentations/references/templates.md +31 -60
- package/assets/skills/office-presentations/routing/google_slides.md +4 -4
- package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
- package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
- package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
- package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
- package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
- package/assets/skills/office-presentations/tasks/template-following.md +23 -28
- package/assets/skills/office-spreadsheets/SKILL.md +32 -39
- package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
- package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
- package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
- package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
- package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
- package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
- package/assets/skills/office-spreadsheets/references/charts.md +15 -34
- package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
- package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
- package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
- package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
- package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
- package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
- package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
- package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
- package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
- package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
- package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
- package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
- package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
- package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
- package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
- package/assets/skills/shared/annotation-recipes.md +98 -120
- package/assets/skills/shared/common-workflow.md +70 -80
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Native charts
|
|
2
2
|
|
|
3
|
-
A native chart is an object bound to cell ranges: the numbers stay in cells, the
|
|
4
|
-
chart reads them, and editing a cell moves the bar. That is the whole reason to
|
|
5
|
-
add one instead of pasting an image.
|
|
3
|
+
A native chart is an object bound to cell ranges: the numbers stay in cells, the chart reads them, and editing a cell moves the bar. That is the whole reason to add one instead of pasting an image.
|
|
6
4
|
|
|
7
5
|
```python
|
|
8
6
|
import sys
|
|
@@ -30,37 +28,21 @@ wb.save(sys.argv[2])
|
|
|
30
28
|
|
|
31
29
|
## Orientation is the bug people hit
|
|
32
30
|
|
|
33
|
-
A one-row source is **one series of many points**, not many series of one point.
|
|
34
|
-
`Reference` cannot express that; `add_data(..., from_rows=True)` can. Without it
|
|
35
|
-
a monthly row becomes twelve invisible one-point series and the chart renders
|
|
36
|
-
blank. The mirror case is a one-column source added with `from_rows=True`: you
|
|
37
|
-
get one series per cell row, so only pass it when the data really is row-wise.
|
|
31
|
+
A one-row source is **one series of many points**, not many series of one point. `Reference` cannot express that; `add_data(..., from_rows=True)` can. Without it a monthly row becomes twelve invisible one-point series and the chart renders blank. The mirror case is a one-column source added with `from_rows=True`: you get one series per cell row, so pass it only when the data really is row-wise.
|
|
38
32
|
|
|
39
33
|
## What the helper CLI gives you
|
|
40
34
|
|
|
41
|
-
`xlsx create` accepts `charts[]` with `type`, `title`, `anchor`,
|
|
42
|
-
`height`/`width`, `data {min_col,min_row,max_col,max_row,titles_from_data}` and
|
|
43
|
-
`categories`. `container_tools/add_chart.py` adds the same chart to an existing
|
|
44
|
-
file and handles the row-oriented case. Neither sets axis number formats, series
|
|
45
|
-
colours, legend position, data labels, or gap width — if the chart needs those,
|
|
46
|
-
use a snippet like the one above.
|
|
35
|
+
`xlsx create` accepts `charts[]` with `type`, `title`, `anchor`, `height`/`width`, `data {min_col,min_row,max_col,max_row,titles_from_data}` and `categories`. `container_tools/add_chart.py` adds the same chart to an existing file and handles the row-oriented case. Neither sets axis number formats, series colours, legend position, data labels, or gap width — if the chart needs those, use a snippet like the one above.
|
|
47
36
|
|
|
48
37
|
## Checks before you present
|
|
49
38
|
|
|
50
39
|
- Series count matches the intent (one line per series, not one per point).
|
|
51
40
|
- Categories are labels, not values and not an empty axis with `1, 2, 3, …`.
|
|
52
|
-
- Bar, column, and area axes start at zero; line and scatter may narrow the
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
- Axis number formats are set on the chart, not inherited from cells — a source
|
|
57
|
-
column formatted as `0.0%` does not format the axis.
|
|
58
|
-
- The chart sits near its data, over empty cells, and is not clipped by the
|
|
59
|
-
print area when the sheet is printed.
|
|
41
|
+
- Bar, column, and area axes start at zero; line and scatter may narrow the range, but the scale must be visible and stated.
|
|
42
|
+
- No default legend on a single series; name each series in `titles_from_data` or the legend reads `Series 1`.
|
|
43
|
+
- Axis number formats are set on the chart, not inherited from cells — a source column formatted as `0.0%` does not format the axis.
|
|
44
|
+
- The chart sits near its data, over empty cells, and is not clipped by the print area when the sheet is printed.
|
|
60
45
|
|
|
61
46
|
## Editing a chart in an existing file
|
|
62
47
|
|
|
63
|
-
Read the object first (`inspect_workbook.py` lists type, anchor, and series
|
|
64
|
-
refs), change the smallest property, and re-render. Moving a chart a few cells is
|
|
65
|
-
fine; rebuilding it with different styling when the user asked for one number to
|
|
66
|
-
be added is not.
|
|
48
|
+
Read the object first (`inspect_workbook.py` lists type, anchor, and series refs), change the smallest property, and re-render. Moving a chart a few cells is fine; rebuilding it with different styling when the user asked for one number to be added is not.
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# Conditional formats
|
|
2
2
|
|
|
3
|
-
Conditional formatting paints a cell from a rule, not from a value. The rule is
|
|
4
|
-
stored separately from the cell format, so a cell can look red while its stored
|
|
5
|
-
fill stays default — and a reader who copies the value out gets the number, not
|
|
6
|
-
the colour.
|
|
3
|
+
Conditional formatting paints a cell from a rule, not from a value. The rule is stored separately from the cell format, so a cell can look red while its stored fill stays default — and a reader who copies the value out gets the number, not the colour.
|
|
7
4
|
|
|
8
5
|
```python
|
|
9
6
|
import sys
|
|
@@ -39,31 +36,17 @@ ws.conditional_formatting.add(
|
|
|
39
36
|
wb.save(sys.argv[2])
|
|
40
37
|
```
|
|
41
38
|
|
|
42
|
-
- `ColorScaleRule`/`DataBarRule` take a range, not a cell; one rule covers the
|
|
43
|
-
|
|
44
|
-
- `
|
|
45
|
-
|
|
46
|
-
- `
|
|
47
|
-
|
|
48
|
-
- A whole-column range (`D:D`) is cheap to write and slow to render; bound the
|
|
49
|
-
range to the current data (`D2:D13`) and extend it when rows are added.
|
|
50
|
-
- Rules stack in priority order; later rules win only when the earlier ones do
|
|
51
|
-
not match. `stopIfTrue=True` ends the chain — use it when a second rule must
|
|
52
|
-
not repaint an already-flagged cell.
|
|
53
|
-
- Do not also set a static fill on the same cells: the static fill shows through
|
|
54
|
-
where no rule matches and the sheet looks half-formatted.
|
|
39
|
+
- `ColorScaleRule`/`DataBarRule` take a range, not a cell; one rule covers the rectangle and scales against the values inside it.
|
|
40
|
+
- `CellIsRule` compares one cell: `operator` in `lessThan`, `greaterThan`, `between`, `equal`, `notEqual`, …
|
|
41
|
+
- `FormulaRule` evaluates a formula with the range's **top-left** cell, so write the reference for that cell (`$F2` with row relative) and Excel fills the rest.
|
|
42
|
+
- A whole-column range (`D:D`) is cheap to write and slow to render; bound the range to the current data (`D2:D13`) and extend it when rows are added.
|
|
43
|
+
- Rules stack in priority order; later rules win only when the earlier ones do not match. `stopIfTrue=True` ends the chain — use it when a second rule must not repaint an already-flagged cell.
|
|
44
|
+
- Do not also set a static fill on the same cells: the static fill shows through where no rule matches and the sheet looks half-formatted.
|
|
55
45
|
|
|
56
46
|
## Editing an existing file
|
|
57
47
|
|
|
58
|
-
Replace a rule
|
|
59
|
-
`ws.conditional_formatting` and rebuild the collection for that range. Two rules
|
|
60
|
-
covering `D2:D13` with slightly different thresholds give a result nobody can
|
|
61
|
-
explain. Keep the rule count per sheet small — a dashboard with forty rules is a
|
|
62
|
-
compatibility minefield in other engines.
|
|
48
|
+
Replace a rule; do not add a near-duplicate. Iterate `ws.conditional_formatting` and rebuild the collection for that range — two rules covering `D2:D13` with slightly different thresholds give a result nobody can explain. Keep the rule count per sheet small: a dashboard with forty rules is a compatibility minefield in other engines.
|
|
63
49
|
|
|
64
50
|
## Verify
|
|
65
51
|
|
|
66
|
-
Read the file back with `container_tools/inspect_workbook.py`; it lists each
|
|
67
|
-
range and rule type. Then render and look: a data bar that never appears is
|
|
68
|
-
usually a range that does not overlap the data, and a rule that fires on the
|
|
69
|
-
wrong cells is almost always an absolute/relative mistake in `FormulaRule`.
|
|
52
|
+
Read the file back with `container_tools/inspect_workbook.py`; it lists each range and rule type. Then render and look: a data bar that never appears is usually a range that does not overlap the data, and a rule that fires on the wrong cells is almost always an absolute/relative mistake in `FormulaRule`.
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
# Data tables (Excel Tables)
|
|
2
2
|
|
|
3
|
-
An Excel Table (`ListObject`) is the object behind `Insert > Table`: a name, a
|
|
4
|
-
structured reference, banded rows, an optional totals row, and header filters.
|
|
5
|
-
It is not a pivot table and not a formatted range. Use it when the user asks for
|
|
6
|
-
a table, when a filter row helps, or when formulas should read
|
|
7
|
-
`Sales[Amount]` instead of `$D$2:$D$900`.
|
|
3
|
+
An Excel Table (`ListObject`) is the object behind `Insert > Table`: a name, a structured reference, banded rows, an optional totals row, and header filters. It is not a pivot table and not a formatted range. Use it when the user asks for a table, when a filter row helps, or when formulas should read `Sales[Amount]` instead of `$D$2:$D$900`.
|
|
8
4
|
|
|
9
5
|
```python
|
|
10
6
|
import sys
|
|
@@ -23,19 +19,14 @@ wb.save(sys.argv[2])
|
|
|
23
19
|
|
|
24
20
|
Rules that survive contact with the user:
|
|
25
21
|
|
|
26
|
-
- `displayName` has no spaces, no hyphens, and must be unique in the workbook — it
|
|
27
|
-
|
|
28
|
-
- `ref` must start at the header row and match the real data rectangle. A table
|
|
29
|
-
whose `ref` is off by one row shows a phantom header and breaks the filter.
|
|
22
|
+
- `displayName` has no spaces, no hyphens, and must be unique in the workbook — it becomes the structured reference name (`PipelineTable[Amount]`).
|
|
23
|
+
- `ref` must start at the header row and match the real data rectangle. A table whose `ref` is off by one row shows a phantom header and breaks the filter.
|
|
30
24
|
- One table per rectangle, one header row, no merged cells inside it.
|
|
31
|
-
- Give it a style from `TableStyleLight*`/`Medium*`/`Dark*`; a bare table with no
|
|
32
|
-
style looks like an unstyled range and the user asks why the stripes went away.
|
|
25
|
+
- Give it a style from `TableStyleLight*`/`Medium*`/`Dark*`; a bare table with no style looks like an unstyled range and the user asks why the stripes went away.
|
|
33
26
|
|
|
34
27
|
## Appending rows to a table
|
|
35
28
|
|
|
36
|
-
Rows written below the last table row are outside the table until you widen
|
|
37
|
-
`ref`. Widen it in the same pass, or the new records will not filter, will not
|
|
38
|
-
band, and structured references will not see them.
|
|
29
|
+
Rows written below the last table row are outside the table until you widen `ref`. Widen it in the same pass, or the new records will not filter, will not band, and structured references will not see them.
|
|
39
30
|
|
|
40
31
|
```python
|
|
41
32
|
table = ws.tables["PipelineTable"]
|
|
@@ -44,15 +35,8 @@ new_last = first_row + added
|
|
|
44
35
|
table.ref = f"A1:G{new_last}" # same columns, one row longer
|
|
45
36
|
```
|
|
46
37
|
|
|
47
|
-
Copy the format and any formula from the previous row (`ws.cell(r, c)._style =
|
|
48
|
-
ws.cell(r - 1, c)._style`) before widening, so the new row does not appear as a
|
|
49
|
-
plain block inside a banded table.
|
|
38
|
+
Copy the format and any formula from the previous row (`ws.cell(r, c)._style = ws.cell(r - 1, c)._style`) before widening, so the new row does not appear as a plain block inside a banded table.
|
|
50
39
|
|
|
51
40
|
## Totals row
|
|
52
41
|
|
|
53
|
-
`table.totalsRowCount = 1` declares a totals row, and `totalsRowFunction` on a
|
|
54
|
-
column sets `sum`, `count`, `average`, `min`, `max`, `stdDev`, or `var`. The row
|
|
55
|
-
below the last data row must exist and hold the header labels Excel expects; a
|
|
56
|
-
totals row declared without that row renders oddly in some engines. If the user
|
|
57
|
-
only wants a bold total line under a table, a formula row outside the table is
|
|
58
|
-
simpler and less fragile.
|
|
42
|
+
`table.totalsRowCount = 1` declares a totals row, and `totalsRowFunction` on a column sets `sum`, `count`, `average`, `min`, `max`, `stdDev`, or `var`. The row below the last data row must exist and hold the header labels Excel expects; a totals row declared without that row renders oddly in some engines. If the user only wants a bold total line under a table, a formula row outside the table is simpler and less fragile.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Named ranges
|
|
2
2
|
|
|
3
|
-
A defined name is a saved reference with a readable name: `Q4Growth` instead of
|
|
4
|
-
`Model!$B$6`. Formulas that use names survive row and column insertion, and the
|
|
5
|
-
user can select the name box instead of hunting for a cell.
|
|
3
|
+
A defined name is a saved reference with a readable name: `Q4Growth` instead of `Model!$B$6`. Formulas that use names survive row and column insertion, and the user can select the name box instead of hunting for a cell.
|
|
6
4
|
|
|
7
5
|
```python
|
|
8
6
|
import sys
|
|
@@ -15,27 +13,16 @@ wb.defined_names["PlanRevenue"] = DefinedName("PlanRevenue", attr_text="Model!$B
|
|
|
15
13
|
wb.save(sys.argv[2])
|
|
16
14
|
```
|
|
17
15
|
|
|
18
|
-
- The name must be a legal identifier: letters, digits, underscore, not a cell
|
|
19
|
-
|
|
20
|
-
- `
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
put it on the worksheet: `wb["Model"].defined_names["Rate"] = ...` — the same
|
|
24
|
-
name can then mean different cells on different sheets, which confuses readers
|
|
25
|
-
unless the workbook already works that way.
|
|
26
|
-
- Read the existing names with `container_tools/inspect_workbook.py` before
|
|
27
|
-
adding one; a duplicate name is a repair prompt in Excel.
|
|
28
|
-
- Never point a name at a range whose size changes (`A2:A900`) unless the sheet
|
|
29
|
-
really ends there; prefer the exact used range, or a table reference.
|
|
16
|
+
- The name must be a legal identifier: letters, digits, underscore, not a cell address (`Q4` alone is a column, so it is refused).
|
|
17
|
+
- `attr_text` is a full sheet reference; quote sheet names with spaces: `'Case A'!$B$4`.
|
|
18
|
+
- Workbook-level names live in `wb.defined_names`. To scope a name to one sheet, put it on the worksheet: `wb["Model"].defined_names["Rate"] = ...` — the same name can then mean different cells on different sheets, which confuses readers unless the workbook already works that way.
|
|
19
|
+
- Read the existing names with `container_tools/inspect_workbook.py` before adding one; a duplicate name is a repair prompt in Excel.
|
|
20
|
+
- Never point a name at a range whose size changes (`A2:A900`) unless the sheet really ends there; prefer the exact used range, or a table reference.
|
|
30
21
|
|
|
31
22
|
## Using names in formulas
|
|
32
23
|
|
|
33
|
-
`=PlanRevenue*Q4Growth` is more readable than `=Model!$B$11*Model!$B$6`, and it
|
|
34
|
-
does not break when a row is inserted. Paste the formula text exactly as the user
|
|
35
|
-
would type it; openpyxl never resolves the name.
|
|
24
|
+
`=PlanRevenue*Q4Growth` is more readable than `=Model!$B$11*Model!$B$6`, and it does not break when a row is inserted. Paste the formula text exactly as the user would type it; openpyxl never resolves the name.
|
|
36
25
|
|
|
37
26
|
## Removing a name
|
|
38
27
|
|
|
39
|
-
Deleting a name leaves every formula that used it as `#NAME?`. Find the users
|
|
40
|
-
first (formula text is visible in `inspect_workbook.py` output and
|
|
41
|
-
`xlsx read`), then delete, then recalculate and check the gate.
|
|
28
|
+
Deleting a name leaves every formula that used it as `#NAME?`. Find the users first (formula text is visible in `inspect_workbook.py` output and `xlsx read`), then delete, then recalculate and check the gate.
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
# Number formats
|
|
2
2
|
|
|
3
|
-
A number format changes how a stored value is displayed, never the value. The
|
|
4
|
-
cell keeps full precision; `0.0%` shows `6.4%` for `0.06398`. Never store a
|
|
5
|
-
rounded number to make a column look tidy, and never store `"6.4%"` as text —
|
|
6
|
-
it stops summing.
|
|
3
|
+
A number format changes how a stored value is displayed, never the value. The cell keeps full precision; `0.0%` shows `6.4%` for `0.06398`. Never store a rounded number to make a column look tidy, and never store `"6.4%"` as text — it stops summing.
|
|
7
4
|
|
|
8
5
|
```python
|
|
9
6
|
import sys
|
|
@@ -42,31 +39,18 @@ wb.save(sys.argv[2])
|
|
|
42
39
|
| Date | `yyyy-mm-dd` | Sortable, unambiguous; store a real date, not text |
|
|
43
40
|
| Text passthrough | `@` | For codes and account numbers with leading zeros |
|
|
44
41
|
|
|
45
|
-
Do not use `0,0%` or `#.##0`. They are not locale-independent and render
|
|
46
|
-
differently on an engine that reads `,` as a decimal separator.
|
|
42
|
+
Do not use `0,0%` or `#.##0`. They are not locale-independent and render differently on an engine that reads `,` as a decimal separator.
|
|
47
43
|
|
|
48
44
|
## Signs, units, and scale
|
|
49
45
|
|
|
50
|
-
- State the unit once, in the header or title (`Revenue (USD)`), and keep the
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- If the presentation needs thousands (`$K`) while the data is in units,
|
|
54
|
-
format does not divide — either store thousands and say so, or divide with a
|
|
55
|
-
formula in a helper column. Never scale twice.
|
|
56
|
-
- Percentages: store `0.064`, never `6.4`. A stored `6.4` formatted `0.0%`
|
|
57
|
-
reads `640.0%`.
|
|
46
|
+
- State the unit once, in the header or title (`Revenue (USD)`), and keep the stored value in that unit. A column that stores thousands but is headed "USD" is a defect waiting to be discovered.
|
|
47
|
+
- If the presentation needs thousands (`$K`) while the data is in units, format does not divide — either store thousands and say so, or divide with a formula in a helper column. Never scale twice.
|
|
48
|
+
- Percentages: store `0.064`, never `6.4`. A stored `6.4` formatted `0.0%` reads `640.0%`.
|
|
58
49
|
|
|
59
50
|
## Widths and `###`
|
|
60
51
|
|
|
61
|
-
`###` means the column is narrower than the formatted number. Widen that
|
|
62
|
-
column (`ws.column_dimensions["B"].width = 14`) or shrink the font for the block.
|
|
63
|
-
Never shorten the number, switch to text, or reduce decimals just to fit — and do
|
|
64
|
-
not autofit every column in the sheet to fix one.
|
|
52
|
+
`###` means the column is narrower than the formatted number. Widen that column (`ws.column_dimensions["B"].width = 14`) or shrink the font for the block. Never shorten the number, switch to text, or reduce decimals just to fit — and do not autofit every column in the sheet to fix one.
|
|
65
53
|
|
|
66
54
|
## Dates
|
|
67
55
|
|
|
68
|
-
Write a real date (`datetime.date(2026, 1, 31)`) and set `yyyy-mm-dd`.
|
|
69
|
-
an ISO string sorts alphabetically and calculates as text: `EDATE`, `SUMIFS` on
|
|
70
|
-
dates, and `YEAR()` all fail silently or with `#VALUE!`. A date typed as a number
|
|
71
|
-
of days since 1899-12-30 is a serial — fine for formulas, unreadable for people,
|
|
72
|
-
so format it.
|
|
56
|
+
Write a real date (`datetime.date(2026, 1, 31)`) and set `yyyy-mm-dd`. An ISO string sorts alphabetically and calculates as text: `EDATE`, `SUMIFS` on dates, and `YEAR()` all fail silently or with `#VALUE!`. A date typed as a number of days since 1899-12-30 is a serial — fine for formulas, unreadable for people, so format it.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Sparklines and in-cell bars
|
|
2
2
|
|
|
3
|
-
openpyxl writes no sparkline object (and neither does the helper CLI), so a
|
|
4
|
-
"sparkline" here is one of two things: a formula that draws a bar inside the
|
|
5
|
-
cell, or a tiny native chart. Pick by what the user needs to read.
|
|
3
|
+
openpyxl writes no sparkline object (and neither does the helper CLI), so a "sparkline" here is one of two things: a formula that draws a bar inside the cell, or a tiny native chart. Pick by what the user needs to read.
|
|
6
4
|
|
|
7
5
|
```python
|
|
8
6
|
import sys
|
|
@@ -21,23 +19,12 @@ ws.row_dimensions[4].height = 14
|
|
|
21
19
|
wb.save(sys.argv[2])
|
|
22
20
|
```
|
|
23
21
|
|
|
24
|
-
- `REPT` needs a repeat count that fits the column. A 9-character column shows
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
- The block character is text. Sorting the column sorts blocks, and a reader who
|
|
30
|
-
copies the cell gets `████`, not a number — never put these in the column the
|
|
31
|
-
numbers should be read from.
|
|
32
|
-
- Guard blanks with `IF(cell="","",…)`, otherwise a blank reads as zero and every
|
|
33
|
-
missing month draws a minimum bar.
|
|
34
|
-
- A native in-cell chart is not the same as a chart object: if the user needs a
|
|
35
|
-
hover tooltip, axis, or legend, build a real chart with `recipes/charts.md`
|
|
36
|
-
instead of stretching a formula.
|
|
22
|
+
- `REPT` needs a repeat count that fits the column. A 9-character column shows about 7 blocks at 9pt; anything longer spills into the neighbouring cell and the bars look like one continuous smear. Scale to the column width, not to 22.
|
|
23
|
+
- Keep the count formula-driven (`value / MAX(values) * width`), so a changed number moves the bar.
|
|
24
|
+
- The block character is text. Sorting the column sorts blocks, and a reader who copies the cell gets `████`, not a number — never put these in the column the numbers should be read from.
|
|
25
|
+
- Guard blanks with `IF(cell="","",…)`, otherwise a blank reads as zero and every missing month draws a minimum bar.
|
|
26
|
+
- An in-cell native chart is not the same as a chart object: if the user needs a hover tooltip, axis, or legend, build a real chart with `recipes/charts.md` instead of stretching a formula.
|
|
37
27
|
|
|
38
28
|
## When a real chart is the right answer
|
|
39
29
|
|
|
40
|
-
A sparkline is context for one number, in a dense table. If the sheet has space
|
|
41
|
-
and the point is the trend itself, a small `LineChart` (height 4, width 9, no
|
|
42
|
-
legend, no gridlines) reads better and stays editable. Two or three word-sized
|
|
43
|
-
charts beat a wall of block characters.
|
|
30
|
+
A sparkline is context for one number, in a dense table. If the sheet has space and the point is the trend itself, a small `LineChart` (height 4, width 9, no legend, no gridlines) reads better and stays editable. Two or three word-sized charts beat a wall of block characters.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# Chart choice and audit
|
|
2
2
|
|
|
3
|
-
A chart earns its place when it makes a comparison, a trend, a distribution, or a
|
|
4
|
-
relationship easier to see than a table would. If the reader only needs the
|
|
5
|
-
figures, a compact table or a KPI tile is better — and cheaper to check.
|
|
3
|
+
A chart earns its place when it makes a comparison, a trend, a distribution, or a relationship easier to see than a table would. If the reader only needs the figures, a compact table or a KPI tile is better — and cheaper to check.
|
|
6
4
|
|
|
7
5
|
| Question | Default | Notes |
|
|
8
6
|
| --- | --- | --- |
|
|
@@ -16,48 +14,31 @@ figures, a compact table or a KPI tile is better — and cheaper to check.
|
|
|
16
14
|
|
|
17
15
|
## Honesty
|
|
18
16
|
|
|
19
|
-
- Series must read from cells, not
|
|
20
|
-
|
|
21
|
-
- Include zero on bar, column, and area axes. Narrowing a line or scatter axis is
|
|
22
|
-
acceptable when the limits are stated; a truncated bar axis turns a 5% change
|
|
23
|
-
into a dramatic cliff.
|
|
17
|
+
- Series must read from cells, not typed arrays, and derived values must be formulas. A chart of pasted numbers drifts the moment the table updates.
|
|
18
|
+
- Include zero on bar, column, and area axes. Narrowing a line or scatter axis is acceptable when the limits are stated; a truncated bar axis turns a 5% change into a dramatic cliff.
|
|
24
19
|
- No 3-D, no shadows, no gradients. They occlude data and date the workbook.
|
|
25
|
-
- One period, one baseline, one unit across comparable charts. Disclose omitted
|
|
26
|
-
|
|
27
|
-
- Sort categories deliberately (by value, or by the natural order of time), and
|
|
28
|
-
keep the same order across charts that will be compared.
|
|
20
|
+
- One period, one baseline, one unit across comparable charts. Disclose omitted periods and missing values; do not let a blank read as zero.
|
|
21
|
+
- Sort categories deliberately (by value, or by the natural order of time), and keep the same order across charts that will be compared.
|
|
29
22
|
|
|
30
23
|
## Formatting rules that catch reviewers' eyes
|
|
31
24
|
|
|
32
|
-
- Title states subject and unit: `Profit by category ($m)`, `Monthly revenue
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
- Few series: direct labels. More series: legend above the plot area, consistent
|
|
39
|
-
colours per series across the workbook.
|
|
40
|
-
- Single series: no legend, one colour. A reference or target line is neutral or
|
|
41
|
-
dashed so it does not read as another data series.
|
|
42
|
-
- Selective data labels only — the last point, the maximum, the one the user asked
|
|
43
|
-
about. Ten labels on a twelve-point line is a table with extra steps.
|
|
25
|
+
- Title states subject and unit: `Profit by category ($m)`, `Monthly revenue (USD)`. No placeholder titles, no legend standing in for a title.
|
|
26
|
+
- Units in the title or on the axis: `($K)`, `($M)`, `(USD thousands)`. Never `($000)`.
|
|
27
|
+
- Axis number formats are set on the chart. Source cell formats do not carry over, and a `0.0%` column can still produce `0.06, 0.08` ticks.
|
|
28
|
+
- Few series: direct labels. More series: legend above the plot area, consistent colours per series across the workbook.
|
|
29
|
+
- Single series: no legend, one colour. A reference or target line is neutral or dashed so it does not read as another data series.
|
|
30
|
+
- Selective data labels only — the last point, the maximum, the one the user asked about. Ten labels on a twelve-point line is a table with extra steps.
|
|
44
31
|
- Line strokes are set explicitly; a fill alone may not colour an exported line.
|
|
45
32
|
|
|
46
33
|
## Placement
|
|
47
34
|
|
|
48
|
-
Charts sit next to the data they describe, aligned to a column edge, over empty
|
|
49
|
-
cells, and never over the data, the controls, or a note. Size them to their
|
|
50
|
-
content; a chart stretched across the page with two bars in it looks unfinished.
|
|
35
|
+
Charts sit next to the data they describe, aligned to a column edge, over empty cells, and never over the data, the controls, or a note. Size them to their content; a chart stretched across the page with two bars looks unfinished.
|
|
51
36
|
|
|
52
37
|
## Verifying a chart
|
|
53
38
|
|
|
54
39
|
1. Read the object back: type, anchor, series count, category source.
|
|
55
|
-
2. Render and look at the image: are there categories, is anything clipped, is the
|
|
56
|
-
legend empty, do the bars reach the values in the table?
|
|
40
|
+
2. Render and look at the image: are there categories, is anything clipped, is the legend empty, do the bars reach the values in the table?
|
|
57
41
|
3. Compare the visual against the sheet's numbers at one or two points.
|
|
58
|
-
4. Re-open in the app the user will use if the colours matter — an authoring
|
|
59
|
-
preview is not proof that a filled series exports as a visible line.
|
|
42
|
+
4. Re-open in the app the user will use if the colours matter — an authoring preview is not proof that a filled series exports as a visible line.
|
|
60
43
|
|
|
61
|
-
If the chart cannot be delivered as asked (the engine has no box plot, the data
|
|
62
|
-
cannot be rearranged), say so and use the closest clear alternative. Never claim a
|
|
63
|
-
requirement was met by a chart that does not show it.
|
|
44
|
+
If the chart cannot be delivered as asked (the engine has no box plot, the data cannot be rearranged), say so and use the closest clear alternative. Never claim a requirement was met by a chart that does not show it.
|
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
# Financial models
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
industry.
|
|
3
|
+
Forecasts, budgets, cash-flow plans, and valuation work in any industry.
|
|
5
4
|
|
|
6
|
-
- Periods run left to right with the scale in the header (Actual, Forecast,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
flow, the balance sheet must balance and closing cash must equal the cash-flow
|
|
15
|
-
ending balance. Add those as checks, not as comments.
|
|
16
|
-
- Working capital moves: receivables from revenue × DSO, payables from cost × DPO,
|
|
17
|
-
inventory from COGS × days. Hard-coded changes in working capital break when the
|
|
18
|
-
drivers move.
|
|
19
|
-
- Scenarios: one selector, one set of case inputs per driver, and an explicit
|
|
20
|
-
`Case Selected:` on each output. A workbook with two switch cells reports two
|
|
21
|
-
answers.
|
|
22
|
-
- Never hard-code a total that already exists as a sum, and never sum a column that
|
|
23
|
-
already contains a total (double counting is silent).
|
|
24
|
-
- Sensitivity: one or two variables, closed-form or a small grid with the base case
|
|
25
|
-
marked. A native What-If Data Table is a different object with its own limits —
|
|
26
|
-
only build one when the user asks for it and the engine supports it.
|
|
5
|
+
- Periods run left to right with the scale in the header (Actual, Forecast, Budget). Do not mix a monthly column with a quarterly total in the same row unless a labelled total column sits at the edge.
|
|
6
|
+
- Drivers first, results second: volume × price, headcount × cost, days × rate. A revenue row that jumps straight to a number cannot be reviewed.
|
|
7
|
+
- State units once and keep them: thousands and millions in the same block is the classic reconciliation failure. Put the unit in the title, not a footnote.
|
|
8
|
+
- Three statements or none: if the workbook has a balance sheet and a cash flow, the balance sheet must balance and closing cash must equal the cash-flow ending balance. Make these checks, not comments.
|
|
9
|
+
- Working capital moves: receivables from revenue × DSO, payables from cost × DPO, inventory from COGS × days. Hard-coded working-capital changes break when drivers move.
|
|
10
|
+
- Scenarios: one selector, one set of case inputs per driver, and an explicit `Case Selected:` on each output. Two switch cells report two answers.
|
|
11
|
+
- Never hard-code a total that exists as a sum, and never sum a column that already holds a total — double counting is silent.
|
|
12
|
+
- Sensitivity: one or two variables, closed-form or a small grid with the base case marked. A native What-If Data Table is a different object with its own limits; build one only when the user asks and the engine supports it.
|
|
27
13
|
|
|
28
14
|
## Checks a finance reader looks for first
|
|
29
15
|
|
|
@@ -36,5 +22,4 @@ industry.
|
|
|
36
22
|
| Case consistency | Every tab shows the same selected case |
|
|
37
23
|
| No hard-coded totals | Total cells are formulas |
|
|
38
24
|
|
|
39
|
-
Put them on a check tab, terminal and read-only
|
|
40
|
-
obvious without painting passing checks green.
|
|
25
|
+
Put them on a check tab, terminal and read-only. Make a failing check visually obvious without painting passing checks green.
|
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
# Healthcare operations
|
|
2
2
|
|
|
3
|
-
Workbooks here usually track volume, capacity, cost, and quality — not patients.
|
|
4
|
-
Treat patient-level data as sensitive: do not paste identifiers into a workbook
|
|
5
|
-
unless the user asks for it, do not copy rows from files you were shown into new
|
|
6
|
-
sheets, and prefer aggregates.
|
|
3
|
+
Workbooks here usually track volume, capacity, cost, and quality — not patients. Treat patient-level data as sensitive: do not paste identifiers into a workbook unless the user asks, do not copy rows from files you were shown into new sheets, and prefer aggregates.
|
|
7
4
|
|
|
8
|
-
- Name the denominator in every rate: per patient day, per discharge, per 1,000
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
- Quality and safety metrics keep their own definitions; do not average a rate
|
|
16
|
-
across sites without stating whether it is volume-weighted.
|
|
17
|
-
- Claims and remittance data arrive with gaps. Show missing as blank or `n.a.`,
|
|
18
|
-
never as zero, and state the coverage period.
|
|
19
|
-
- Do not invent clinical thresholds, targets, or compliance claims. Use the
|
|
20
|
-
targets the source file provides, and cite the sheet and cell.
|
|
21
|
-
- Money and counts follow the finance conventions: units stated once, totals as
|
|
22
|
-
formulas, checks that detail rows reconcile to the summary.
|
|
5
|
+
- Name the denominator in every rate: per patient day, per discharge, per 1,000 members, per available bed. A percentage without its base is not a metric.
|
|
6
|
+
- Volume and capacity are different columns. Utilization is `used ÷ available`, and both sides need the same period and unit (bed-days, not beds).
|
|
7
|
+
- Payer mix, service line, and site of care are separate dimensions. One table with a column per dimension beats four tables that must be read together.
|
|
8
|
+
- Quality and safety metrics keep their own definitions; do not average a rate across sites without stating whether it is volume-weighted.
|
|
9
|
+
- Claims and remittance data arrive with gaps. Show missing as blank or `n.a.`, never as zero, and state the coverage period.
|
|
10
|
+
- Do not invent clinical thresholds, targets, or compliance claims. Use the targets the source file provides, and cite the sheet and cell.
|
|
11
|
+
- Money and counts follow the finance conventions: units stated once, totals as formulas, checks that detail rows reconcile to the summary.
|
|
@@ -1,28 +1,14 @@
|
|
|
1
1
|
# Marketing and advertising
|
|
2
2
|
|
|
3
|
-
Campaign work is a funnel plus a spend table, and both are easy to make look
|
|
4
|
-
better than they are.
|
|
3
|
+
Campaign work is a funnel plus a spend table, and both are easy to make look better than they are.
|
|
5
4
|
|
|
6
|
-
- One row per campaign, channel, or creative
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- Never compute a ratio from cells that are not the same period and the same
|
|
13
|
-
population. A monthly CTR built from a quarterly spend and a weekly click count
|
|
14
|
-
is a number nobody can defend.
|
|
15
|
-
- Attribution is a claim: say which model the numbers use (last click, platform
|
|
16
|
-
reported, blended) and keep it constant across the table. Do not add platform
|
|
17
|
-
conversions together and call it incremental revenue.
|
|
18
|
-
- Missing spend or reach for a period is blank, not zero — a zero-spend month
|
|
19
|
-
shows an infinite CPA and a fake collapse in the trend.
|
|
20
|
-
- Benchmarks and targets belong in a labelled row or column with their source, not
|
|
21
|
-
in a note the reader has to find.
|
|
5
|
+
- One row per campaign, channel, or creative, with that grain named in the header. Mixing a channel total into a campaign table double counts.
|
|
6
|
+
- The funnel reads spend → impressions → clicks → conversions → revenue in that order, with rates derived by formula: `CTR = clicks / impressions`, `CVR = conversions / clicks`, `CPA = spend / conversions`, `ROAS = revenue / spend`.
|
|
7
|
+
- Never compute a ratio from cells that are not the same period and the same population. A monthly CTR built from a quarterly spend and a weekly click count is a number nobody can defend.
|
|
8
|
+
- Attribution is a claim: say which model the numbers use (last click, platform reported, blended) and keep it constant across the table. Do not add platform conversions together and call it incremental revenue.
|
|
9
|
+
- Missing spend or reach for a period is blank, not zero — a zero-spend month shows an infinite CPA and a fake collapse in the trend.
|
|
10
|
+
- Benchmarks and targets belong in a labelled row or column with their source, not in a note the reader has to find.
|
|
22
11
|
|
|
23
12
|
## Charts for marketing
|
|
24
13
|
|
|
25
|
-
|
|
26
|
-
two aligned charts. Sort channel bars by spend or by return — not alphabetically —
|
|
27
|
-
and keep the same order across charts. A conversion trend belongs on a line chart
|
|
28
|
-
with the campaign launch dates marked, not on a pie.
|
|
14
|
+
Put spend and return on one chart only when both use the same unit; otherwise two aligned charts. Sort channel bars by spend or by return, not alphabetically, and keep the same order across charts. A conversion trend belongs on a line chart with the campaign launch dates marked, not on a pie.
|
|
@@ -1,22 +1,11 @@
|
|
|
1
1
|
# Scientific and research data
|
|
2
2
|
|
|
3
|
-
The spreadsheet is usually a working copy of measurements, not the record of
|
|
4
|
-
truth. Keep it that way: never edit raw measurements in place, and never let a
|
|
5
|
-
formatted view replace the values behind it.
|
|
3
|
+
The spreadsheet is usually a working copy of measurements, not the record of truth. Keep it that way: never edit raw measurements in place, and never let a formatted view replace the values behind it.
|
|
6
4
|
|
|
7
|
-
- Raw data on its own sheet, untouched, in columns whose headers carry the unit
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
- Keep the precision the instrument gives you and let the format hide extra
|
|
15
|
-
decimals. Rounding stored values destroys the ability to recompute a mean.
|
|
16
|
-
- Uncertainty, detection limits, and excluded points are stated in labelled cells.
|
|
17
|
-
An excluded point stays in the data with a reason column — deleting it hides the
|
|
18
|
-
decision.
|
|
19
|
-
- Smoothing, binning, and unit conversion are formulas with visible inputs, or they
|
|
20
|
-
do not exist. A trend line drawn over noisy points is not an analysis.
|
|
21
|
-
- Distribution, trend, and relationship: choose the chart by the question, and
|
|
22
|
-
check that the axis ranges and bins are stated (`references/charts.md`).
|
|
5
|
+
- Raw data on its own sheet, untouched, in columns whose headers carry the unit (`time (s)`, `temp (C)`, `conc (mg/L)`). Derived columns live on a build sheet and reference the raw cells.
|
|
6
|
+
- One row per observation, one column per variable. Do not encode a variable in a colour, a note, or a header font.
|
|
7
|
+
- Replicates are separate rows with a replicate id and a group id; mean and standard deviation are formulas over those rows, never typed.
|
|
8
|
+
- Keep the precision the instrument gives you and let the format hide extra decimals. Rounding stored values destroys the ability to recompute a mean.
|
|
9
|
+
- State uncertainty, detection limits, and excluded points in labelled cells. An excluded point stays in the data with a reason column — deleting it hides the decision.
|
|
10
|
+
- Smoothing, binning, and unit conversion are formulas with visible inputs, or they do not exist. A trend line drawn over noisy points is not an analysis.
|
|
11
|
+
- Distribution, trend, and relationship: choose the chart by the question, and check that axis ranges and bins are stated (`references/charts.md`).
|