Skip to content

feat(plot)!: take plot colours from the DSE design tokens - #121

Merged
frankbuckley merged 3 commits into
mainfrom
claude/design-token-chart-colours
Oct 7, 2026
Merged

frankbuckley merged 3 commits into
mainfrom
claude/design-token-chart-colours

Conversation

@frankbuckley

@frankbuckley frankbuckley commented Oct 7, 2026 •

Copy link
Copy Markdown
Member

Note

Drafted by a LLM-based AI tool (Claude Code/Opus 5.5).

Summary

The shared plot styles now take their colours from the DSE design tokens, so research figures follow the DSE design language and a group has the same colour in a research figure as on DSE's websites.

  • plot/design_tokens/colors.json is the research colour file generated by dsegroup/apps-common, pinned by its hash in design-tokens.pin.json. A new test fails if the copy changes. The pin leaves out the usual $schema, which points into an internal repository.
  • CHART_COLOURS (chart-1 to chart-6) are the default colour cycle and categorical_palette()'s default, in place of tab10.
  • sequential_palette(n) and diverging_palette(n) return three to five ordered steps, each reaching 3:1 against the white background: blue from least to most, or orange (low, negative) to blue (high, positive) with a grey middle step.
  • SEQUENTIAL_CMAP and DIVERGING_CMAP are registered as dse_sequential and dse_diverging, with _r reversals. The sequential scale replaces tab10 as the default image.cmap, and viridis as plot_heatmap's default. plot_heatmap(..., centre=0.0) centres the diverging scale, for example for correlations.
  • TEXT_COLOUR, LINE_COLOUR and the new MUTED_TEXT_COLOUR and BACKGROUND_COLOUR take the design language's text, hairline, secondary text and background colours.
  • The Python readme and the agent instructions describe the colours.

Breaking changes

Consumers pin a release tag, so nothing changes for them until they bump.

  • categorical_palette(n) raises ValueError for more than six series. The design language allows six categorical series: group the smallest, use small multiples or label series directly. A named matplotlib palette keeps the old behaviour, for example categorical_palette(12, palette="tab20").
  • categorical_palette(n) without a palette returns hex strings, not RGBA tuples. Code that passes the colours to matplotlib or to_rgb() is unaffected; code that indexes a colour's channels must convert it first.
  • The default colour cycle, image.cmap and plot_heatmap colours change, as do TEXT_COLOUR (#333333 to #202020) and LINE_COLOUR (#c0c0c0 to #d2d8df). Draw a reference line that carries meaning, such as zero, in MUTED_TEXT_COLOUR.
  • The COLOUR_* hues are deprecated and raise DeprecationWarning:
Name Returns Replace with
COLOUR_BLUE, COLOUR_GREEN, COLOUR_ORANGE, COLOUR_PURPLE CHART_COLOURS[0] to CHART_COLOURS[3] The same CHART_COLOURS entry
COLOUR_RED, COLOUR_YELLOW, COLOUR_DARK_* Their old values A CHART_COLOURS entry by series order, or an ordered step

Known consumer changes

Each project changes only when it bumps, but these call sites need attention then:

  • vocabulary-growth descriptive.py _shared_group_colours asks for len(groups) + extra colours and drops "reddish" ones. Its rule counts chart-3 orange as reddish, so six or more groups raise ValueError. It needs grouping, small multiples or an explicit palette.
  • vocabulary-growth draws zero and reference lines in LINE_COLOUR, and time_to_milestone.py writes annotation text in it. LINE_COLOUR gets lighter, from 1.8:1 to 1.4:1 on white, so those belong in MUTED_TEXT_COLOUR.
  • language-reading-predictors base_pipeline.py draws Spearman correlations with plot_heatmap. The default sequential scale puts negative correlations at its quiet end, so those calls should pass centre=0.0.
  • language-reading-predictors imports COLOUR_BLUE, COLOUR_ORANGE and COLOUR_RED in its package modules. Python hides a DeprecationWarning raised outside __main__, so the warnings show only under pytest; blue and orange change colour on bump.

Before merging

This pins an unreleased file from dsegroup/apps-common, where these palettes are now merged and approved. Once a design token release includes them, re-copy dist/research/colors.json at the release tag and set the pin's tag and sha256. Until then the pin's tag is unreleased.

Squash merge with a message that leaves out the first commit's internal issue reference.

Validation

  • uv run pytest: 1210 passed, 15 skipped. The tests cover the pin, 3:1 contrast for every chart colour and ordered step, the palettes, the deprecated names, the default style and the heatmap's scales.
  • uv run ruff check src/python and uv run ruff format --check src/python pass.
  • npm run spellcheck and npm run format:check pass.
  • uv build --package dse-research-utils: the wheel includes design_tokens/colors.json.
  • A specimen figure through the new styles showed clear survey bars, categorical series and heatmaps, including under simulated deuteranopia.

🤖 Generated with Claude Code

Vendor the research colours generated by dsegroup/apps-common and pin them
by hash, with a test that fails if the copy changes. The plot styles take
their categorical, ordered and continuous colours and their text, line and
background roles from it:

- CHART_COLOURS (chart-1 to chart-6) is the default colour cycle and
  categorical_palette's default.
- sequential_palette and diverging_palette return three to five ordered
  steps, each reaching 3:1 against the background.
- SEQUENTIAL_CMAP and DIVERGING_CMAP are registered as dse_sequential and
  dse_diverging; the sequential scale is the default image.cmap, and
  plot_heatmap can centre the diverging scale.

BREAKING CHANGE: categorical_palette(n) raises ValueError for more than six
series unless a matplotlib palette is named, the default colour cycle and
image colormap change, and TEXT_COLOUR and LINE_COLOUR take the design
roles. The COLOUR_* hues are deprecated: blue, green, orange and purple
return the chart colours, and the rest keep their old values.

Refs dsegroup/code#7999

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frankbuckley frankbuckley self-assigned this Oct 7, 2026
frankbuckley and others added 2 commits October 7, 2026 14:17
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frankbuckley
frankbuckley marked this pull request as ready for review October 7, 2026 13:27
@frankbuckley
frankbuckley merged commit 493763a into main Oct 7, 2026
7 checks passed
@frankbuckley
frankbuckley deleted the claude/design-token-chart-colours branch October 7, 2026 13:30
frankbuckley added a commit that referenced this pull request Oct 7, 2026
Bump the version, point the install instructions at v0.18.0 and add
upgrade notes for the design-token plot colours from #121 and #122.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
frankbuckley added a commit to dseinternational/vocabulary-growth that referenced this pull request Oct 7, 2026
Select dse-research-utils at a1c2656e7d5c303c4938b04168b9b79cf78b2270, the
commit v0.18.0 will be cut from, by `rev` until the tag exists. Only
dse-research-utils moves in the lock. The library takes its plot colours from
the DSE design tokens (dseinternational/research#121).

The lock test accepts a `rev` selection and checks that the locked commit is
the selected one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant