Add colourblind-safe palette toggle with marker shapes - #131
Conversation
Port tedana's colourblind report encoding (ME-ICA/tedana#1475) to rica. Introduce a single source of truth for classification styling in src/constants/palette.js holding both the default pastel palette and the Okabe-Ito colourblind-safe palette, plus a per-class marker shape. - Add a persisted "colourblind" toggle to ThemeContext (localStorage 'rica-colorblind'), surfaced as a header button beside the theme toggle. - Marker shapes (circle/square/triangle/diamond) always encode class in the scatter plots, independent of palette, as a redundant non-colour cue. - Refactor ScatterPlot, PieChart, ComponentTable, Plots and DecisionTree to consume the shared module instead of duplicated inline getColors() blocks. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ Deploy Preview for rica-fmri ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a centralized classification styling system (colors + redundant marker shapes) and a user-facing toggle to switch to an Okabe–Ito colourblind-safe palette, then refactors existing visual components to consume the shared palette API via useTheme().
Changes:
- Added
src/constants/palette.js(default + colourblind palettes, per-class marker shapes) plus unit tests. - Added a persisted
colorblindflag toThemeContextand a header toggle button to control it. - Refactored DecisionTree + plot components (scatter, pie, tables, time series colours) to use
colorFor(...)/getClassStyle(...).
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/constants/palette.js | New single source of truth for class colors (default + Okabe–Ito) and marker shapes. |
| src/constants/palette.test.js | Unit tests verifying palette exactness, fallback behavior, and selection variants. |
| src/index.js | Adds persisted colorblind state + header toggle; injects new context values. |
| src/Tree/DecisionTree.js | Switches accepted/rejected and time series line colors to colorFor(...); reads colorblind from theme. |
| src/Plots/ScatterPlot.js | Replaces circle-only markers with per-class shapes; uses shared class styling. |
| src/Plots/PieChart.js | Uses shared palette for slice colors (including selected/hover variants). |
| src/Plots/ComponentTable.js | Uses shared palette for row/badge highlighting, now driven by classification. |
| src/Plots/Plots.js | Uses shared palette for toggle/time series/spectrum line colours; reads colorblind from theme. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Extract ThemeContext/useTheme into src/contexts/theme.js so components no longer import from the app entrypoint (index.js has module-level render side effects); fixes the circular-dependency review comments. - Give the colourblind palette lightened dark-mode variants so classes keep their visual punch on the dark background (all >= 3:1 contrast). - Add aria-label + type="button" to the colourblind toggle for screen readers. - Document why DecisionTree uses the saturated shade (colours are rendered as text there, not fills). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks for the review! Addressed in f7d6423:
Also added lightened dark-mode variants to the colourblind palette so the classes keep their punch on the dark background (all ≥ 3:1 contrast), with a test covering them. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/Tree/DecisionTree.js:299
selectedClassificationcurrently collapses any non-"accepted" final classification into "rejected". This means components that end as "ignored", "unclassified", or other intermediate values (e.g. provisional states) will be styled with the rejected colour, which breaks the intended palette/shape consistency (and the colourblind-safe mapping). Consider normalizing the final classification string into one of {accepted,rejected,ignored,other} (e.g. by substring match on accept/reject/ignore) before passing it tocolorFor.
if (!selectedComponent || !componentPaths[selectedComponent]) return "accepted";
const path = componentPaths[selectedComponent];
const finalClass = path.nodes[path.nodes.length - 1]?.classification || path.initial;
return finalClass === "accepted" ? "accepted" : "rejected";
}, [selectedComponent, componentPaths]);
Ports the colourblind report encoding from ME-ICA/tedana#1475 to rica.
What
src/constants/palette.js— a single source of truth for classification styling, replacing thegetColors(isDark)block that was copy-pasted across five files. Holds both the current pastel palette and the Okabe-Ito colourblind-safe palette (accepted#009E73, rejected#D55E00, ignored#0072B2, other#999999), plus a per-class marker shape. Unknown classifications fall back toother.ThemeContext(localStoragerica-colorblind), surfaced as a header button next to the light/dark toggle. Opt-in; default look unchanged.ScatterPlot,PieChart,ComponentTable,Plots, andDecisionTreeto consume the shared module.Notes
colorblindflag viauseTheme()rather than prop-threading through the many render sites.ComponentTablebadge/row andDecisionTreenodes previously lumpedignoredin with the rejected colour; routing through the module now givesignoredits own blue everywhere — a small intended consistency change.Verification
src/constants/palette.test.js(Okabe-Ito exactness, distinct colours/shapes,otherfallback, shape independent of the flag). Full suite passes;react-scripts buildis clean.🤖 Generated with Claude Code