Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 106 additions & 73 deletions CHANGELOG.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion chartwright/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
The LLM is an untrusted parser at the edge; the guarantee lives in typed code.
"""

__version__ = "0.5.0"
__version__ = "0.6.0"
14 changes: 7 additions & 7 deletions chartwright/design/guidelines/composition.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
by side; two unrelated charts sharing a row invite false comparison.
- A row's charts share their time window and grain, or the title says why not.
- One message per chart: a chart needing a paragraph is two charts, or a table.
- Titles state the answer where possible ("Orders fell 12% WoW"), the
question otherwise ("Orders by week"); never just a column name. Filtered
charts name their scope in the title.
- Titles (recommended): the measure, unit and window ("Orders, last 12 weeks"),
numbers only when the spec computes them from data; a typed takeaway ("Orders
fell 12%") goes stale at the next refresh. Never just a column name.
- Tabs split different questions; scrolling deepens one. Never a one-chart tab;
a one- or two-chart sub-tab belongs on its parent page, under a header row.
- Whitespace is markdown's job, sparingly: a one-line header (1.6-2.4 units) beats
Expand All @@ -17,13 +17,13 @@
`{"markdown": "...", "height": 1.6}` is a slim caption.
- One number format per measure across KPIs and axes (`number_format`;
`number_formats` per table column; pivots keep Superset's smart default).
- Color restraint: Superset's default palette, RAG only where a threshold has
a real business meaning; never encode the same dimension with two palettes.
- Colour by role (recommended): one accent for chrome, this period saturated and
the prior period its tint, status green/amber/red beside an arrow or a word, row
tints on status tables. One meaning per colour; never two palettes for one dimension.
- RAG polarity is a convention: red = adverse, green = good (IBCS). Bands on one
metric are disjoint and tell one story; a status-coloured KPI colours only its
exceptions and states its thresholds in its subtitle or description.
- A heatmap's default sequential scale, normalized over the whole map, suits
magnitudes, not signed deltas: don't heatmap a metric that crosses zero.
- Don't heatmap a metric that crosses zero: its sequential scale suits magnitudes.
- Table bars only where size is the point (`cell_bars: ["Revenue"]`), never on
ids or years. Superset tints every bar by sign, green on 6.x even for revenue:
keep that for a change, `color_by_sign: ["Change"]`, listed in cell_bars too.
2 changes: 1 addition & 1 deletion docs/DESIGN-BRAIN.md
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,7 @@ thresholds; those marked judgement are usability choices, not pixel facts.
| `default.page-length` | `page_length` | the whole rows that fit beside the page-size bar and the pager | a table with an explicit `row_limit` larger than the rows that fit on one page, and a page of at least `page_min_rows` (3, judgement). The one grid model `size.table-window` reads, so the fill can never make that rule ask for more height |
| `default.search-box` | `search_box` | `true` | a raw-mode table with an explicit `row_limit` above `search_min_rows` (20, judgement) that outgrows its panel and pages (`page_length` above 0 and below `row_limit`), so the box sits in the bar the page-size picker already draws and hides no row. Never on a table whose rows all show (brain 10; brain 5 to 9 also filled one there when every row still fit beside it) |
| `default.single-series-legend` | `show_legend` | `false` | a timeseries chart or categorical bar with one metric, no groupby, no series limit, no goal lines and no legend placement written, whose shown title or `y_axis_title` contains the metric's label, and that label is at least 3 characters long. Never a heatmap, whose legend is the colour scale |
| `default.value-labels` | `show_value` | `true` | a categorical bar with one metric, no groupby, no `contribution`, an explicit `row_limit` of at most `value_label_max_bars` (12). A vertical bar also needs a width of at least `value_label_min_width` (6/12); a horizontal bar needs the height to space its labels, 4.5 units plus 0.4125 a bar (§17) |
| `default.value-labels` | `show_value` | `true` | a categorical bar with no groupby, no `contribution` and no stacked metrics, an explicit `row_limit`, and at most `value_label_max_bars` (12) bars, counting `row_limit` × metrics for grouped bars (brain 17). A vertical bar also needs a width of at least `value_label_min_width` (6/12); a horizontal bar needs the height to space its labels, 4.5 units plus 0.4125 a bar (§17) |
| `default.heatmap-label-room` | `left_margin` | `16` | every heatmap (brain 12). With no margin, a heatmap's grid starts at the card's edge, and Superset 6.1.0 draws the longest y label wider than the room the grid gave it, cutting off its first letters: seen live on `Trucks and Buses` (95 px) and `Australian Gift Network, Co` (150 px). 8 px cleared the first and 16 px both; 4.1.4 and 5.0.0 drew them whole and only gain 16 px of space. A theme can't fix it, since 6.1.0 renders the heatmap without its chart type and no per-type override reaches it |

`narrative.big-number-format` stands down where `default.count-format`
Expand Down
2 changes: 1 addition & 1 deletion docs/VERIFICATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ injection.

| Layer | Proves | Where it runs |
|---|---|---|
| Offline suite (2421 tests, 78 modules) | Contract, determinism, round-trips, credentials | every PR and push to main, Linux + Windows, mcp 1 and 2 |
| Offline suite (2430 tests, 79 modules) | Contract, determinism, round-trips, credentials | every PR and push to main, Linux + Windows, mcp 1 and 2 |
| Chart-option contract | Every emitted chart option is declared by each version's plugin source | every PR and push to main |
| Live guarantee check | Three specs applied (every chart type, every display control, every dashboard and filter control), per-chart data check, ids stable across re-apply | every PR and push to main, all 3 versions |
| Standards content round trip | `standards apply` writes an org footer, a team header and two CSS blocks into a spec; it applies, `plan` stays clean, decompile reads the CSS markers and every managed row back, `--claim` rebuilds the record, re-apply stays clean | every PR and push to main, all 3 versions |
Expand Down
11 changes: 9 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# The README dashboard

[nyc_taxi_operations.json](nyc_taxi_operations.json) is the spec behind the
README's screenshot. An AI session with this repo's skill wrote it, unedited,
from this request:
README's screenshot. An AI session with this repo's skill wrote it from this
request; the only later edit is its axis titles, added in 0.6.0 when `advise` began
asking for them:

> Build an operations dashboard for NYC yellow taxi trips from the
> nyc_yellow_taxi table in the examples database. I want headline numbers for
Expand Down Expand Up @@ -51,3 +52,9 @@ chartwright apply examples/nyc_taxi_operations.json --profile local

`sandbox/up.sh` prints the `[local]` profile block to save as
`~/.config/chartwright/profiles.toml`.

# Sundown

[sundown/](sundown/) is a six-tab dashboard for siting data centres on the US power
grid, built from EIA-930 and EIA-860M data: its spec, the script that writes it, seven
colour palettes and the Superset theme it names. See [its README](sundown/README.md).
20 changes: 20 additions & 0 deletions examples/sundown/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Sundown

A six-tab dashboard for siting data centres on the US power grid, built from one spec with Chartwright. The data is EIA-930 hourly grid data and EIA-860M. It's the dashboard in Chartwright's README.

## What's here
- `sundown.json`: the spec. `chartwright validate`, `compile` and `advise` run on it as it is.
- `build_spec_sundown.py`: writes the spec from `facts.json` and a palette. `facts.json` holds the numbers the titles and time windows are built from.
- `palettes/`: seven palettes, `coral-teal-v2` by default. A palette sets every colour in the spec (its CSS, label colours and colour rules) and in the theme.
- `theme/`: the Superset theme the spec names (`"theme": "Sundown"`), and a script that creates or updates it through Superset's API.

## Rebuild it in another palette
```sh
python3 build_spec_sundown.py facts.json robins-egg > sundown.json
SUPERSET_URL=https://superset.example.com SUPERSET_PASSWORD=... python3 theme/create_theme.py robins-egg
chartwright apply sundown.json --profile <profile>
```

## What it needs to run
- **`apply` needs the warehouse.** The spec reads a Postgres warehouse with a `sundown` schema built from EIA-930 and EIA-860M, which are public domain. The data pipeline isn't included, so `apply` works only against such a warehouse.
- **The theme needs Superset 6.0 or later.** On 4.1 or 5.0, remove `"theme"` from the dashboard block; the dashboard keeps the colours its CSS sets.
Loading
Loading