Skip to content

CVD-safe default categorical palette#61

Open
FarhanAliRaza wants to merge 1 commit into
mainfrom
cvd-safe-default-palette
Open

CVD-safe default categorical palette#61
FarhanAliRaza wants to merge 1 commit into
mainfrom
cvd-safe-default-palette

Conversation

@FarhanAliRaza

Copy link
Copy Markdown
Contributor

Summary

Replaces the Tableau10 default categorical palette with an eight-slot CVD-safe palette (§20/§36 default theme).

Why: Tableau10's adjacent red/green pair collapsed to ΔE 1.2 under deuteranopia — effectively indistinguishable — and slots 1/5/7/9/10 sat below the chroma floor.

The new palette keeps every step in the OKLCH lightness band shared by light and dark surfaces (L 0.48–0.67) and validates against both reference surfaces (#fcfcfb / #1a1a19):

  • worst adjacent-pair CVD ΔE 8.5 (Machado–Oliveira–Fernandes protan/deutan, ≥8 target)
  • worst adjacent normal-vision ΔE 19.1 (≥15 floor)
  • chroma ≥ 0.10 and ≥3:1 contrast for every slot on both surfaces

The slot order is the safety mechanism — adjacency drives the ΔE gate — so the config comment now warns against re-ordering or extending without re-running the validator.

Also in this PR

  • Updated the hardcoded segment colors in the Reflex demo app and the visual-regression chrome shell to the new slots.
  • Regenerated examples/reflex/assets/charts/*.html, which also picks up the current embedded render client (colormap stops, colorbar chrome CSS) from recent main commits.

Checks

  • pre-commit run --all-files, ruff check, ruff format --check all pass.

@codspeed-hq

codspeed-hq Bot commented Jul 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 94 untouched benchmarks
⏩ 1 skipped benchmark1


Comparing cvd-safe-default-palette (5701f77) with main (8ace307)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

…lette

Tableau10's adjacent red/green collapsed to dE 1.2 under deuteranopia
and half its slots sat below the chroma floor. The new eight-slot
palette keeps every step in the OKLCH lightness band shared by light
and dark surfaces (L 0.48-0.67) and passes the validator on both
reference surfaces: worst adjacent-pair CVD dE 8.5 (>=8 target), worst
adjacent normal-vision dE 19.1 (>=15 floor), all slots >=3:1 contrast.
Slot order is the safety mechanism (adjacency drives the dE gate), so
the palette must be re-validated before any re-order or extension.

Updates the hardcoded segment colors in the Reflex demo app and the
visual-regression chrome shell.
@FarhanAliRaza
FarhanAliRaza force-pushed the cvd-safe-default-palette branch from b605467 to 5701f77 Compare July 17, 2026 17:38
@Alek99

Alek99 commented Jul 19, 2026

Copy link
Copy Markdown
Member

Reviewed — the palette itself is solid, but the committed demo assets don't match the PR description and actively mislabel colors.

Blocking: the regenerated examples/reflex/assets/charts/*.html files are missing from the commit

The PR body says these assets were regenerated, but the diff only touches 3 files and the committed assets still embed the old Tableau10 colors — custom_chrome.html's spec has "palette":["#4c78a8","#f58518","#54a24b"] and density_scatter.html's density overlay has "color":"#4c78a8". Meanwhile the Reflex demo app's custom legend WAS updated to the new hexes, so the swatch-to-mark mapping is now actively wrong: the legend shows a green #008300 swatch for "Growth" while Growth points render orange #f58518, and magenta #d55181 for "Self serve" while those points render green — worse than before the PR. The visual-regression chrome shell (scripts/visual_regression_smoke.py) wraps the same stale asset, so the mismatch also gets baked into regression screenshots, and the DOM probe only checks element visibility so CI won't catch it.

Fix: run examples/reflex/scripts/build_charts.py and commit the regenerated assets.

Non-blocking:

  • The new comment block in python/xy/config.py points at .claude/skills/xy-dataviz/scripts/validate_palette.py, which doesn't exist in the repo — the "re-run the validator before reordering" instruction is unactionable. Either commit the validator or drop the reference.
  • tests/test_scatter_matrix.py:107 comment still says the base palette has 10 entries; it's 8 now (assertions are length-agnostic and still pass).

The palette design itself checks out — I independently reproduced the CVD claims (Machado protan/deutan simulation + Lab ΔE76): the old palette does collapse (#54a24b#e45756 at deutan ΔE76 ≈ 1.7, and 5 slots below 3:1 contrast on light surfaces), while the new one holds worst-case adjacent CVD ΔE76 ≈ 27.6 with contrast 3.05–5.57 on both surface colors. And every palette consumer (Python payload/raster/SVG, JS renderer via the wire palette) indexes modulo length, so shrinking 10→8 is safe; 148 related tests pass.

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.

2 participants