〇 Data Visualization
Plotting & Data Visualization Guidelines
Companion to the SDSC UI Design Kit for scientific plots, charts, and data graphics. Covers colour palettes, colormaps, accessibility, and implementation across Python and JavaScript stacks.
Based on datascience.ch visual identity.
1. Scope and Principles
The UI kit colours are optimized for interface chrome. Plots have different requirements — colours must encode data.
Colours must be distinguishable from each other (not just from the background), perceptually honest (equal data steps should look like equal visual steps), and readable by people with colour vision deficiency — approximately 5% of users.
Colour encodes meaning, never decoration
Every colour in a chart should answer 'what does this colour tell the reader?' If the answer is 'nothing', use one colour.
Never rely on colour alone
Pair colour with direct labels, markers, dash patterns, or annotation. This is the single most effective accessibility measure.
Match palette type to data type
Categorical data → categorical palette. Ordered data → sequential. Meaningful midpoint → diverging. Continuous fields → perceptually uniform colormaps.
2. Chart Colours
Four palette types cover all chart scenarios. Choose the type that matches your data structure.
Categorical Palette
For distinct, unordered categories (line series, grouped bars, scatter groups). Use in this order — it is chosen so the first colours used are the most distinguishable.
Chart Dark Blue
#26235c
1 · SDSC primary
Chart Green
#73a235
2 · Accent green
Chart Orange
#b34a00
3
Chart Sky Blue
#56b4e9
4
Chart Pink
#cc79a7
5
| Order | Name | Hex | Notes |
|---|---|---|---|
| 1 | Chart Dark Blue | #26235c | SDSC primary brand colour |
| 2 | Chart Green | #73a235 | SDSC accent green, darkened for contrast on white |
| 3 | Chart Orange | #b34a00 | |
| 4 | Chart Sky Blue | #56b4e9 | |
| 5 | Chart Pink | #cc79a7 |
Maximum 5 categories
One colour for single-variable bar charts
Focus / Highlight Charts
To draw attention to one series among many, colour it and mute the rest. This scales far beyond 5 series.
Highlighted
#26235cHighlighted (alt)
#73a235Muted context series
#b8b8b8Sequential Palette (Ordered Categories)
For ordered categories (age bands, quintiles, ratings) in legends, stacked bars, or simple choropleths. Shades of brand dark blue with evenly spaced lightness (L* ≈ 18 / 34 / 53 / 72 / 89).
#26235c#4a4889#7a7ab5#aaaed7#dddeecUse 3–5 steps. The lightest steps fall below 3:1 contrast on white — separate areas with thin white/grey borders and label values directly.
Diverging Palette
For data with a meaningful midpoint (above/below zero, agree/disagree). Diverges from a near-neutral centre to brand blue and chart orange.
#26235c#7a7ab5#f0eeeb#cf7d42#b34a00Only use diverging when the midpoint is meaningful
Dark Mode
The categorical palette inverts poorly on dark backgrounds
(#26235c is invisible on #2d2d2d). In dark mode use lightened variants,
and prefer ≤ 4 series.
Dark Blue
#8a94c9
Replaces #26235c
Green
#90ca42
Replaces #73a235
Orange
#e07b39
Replaces #b34a00
Sky Blue
#56b4e9
Unchanged
Pink
#cc79a7
Unchanged
How These Palettes Were Verified
Contrast check
Every categorical colour has ≥ 3:1 contrast against white (WCAG 2.1 SC 1.4.11 for graphical objects).
Colour vision deficiency
Simulated for protanopia, deuteranopia, and tritanopia using Machado et al. 2009 matrices.
Pairwise difference
Minimum pairwise colour difference checked in CIELAB. Tightest pair is Green vs Orange under deuteranopia.
Re-run checks after any palette change
python3 scripts/verify_chart_palettes.py (no dependencies).
For interactive checking use viz-palette or Coblis.3. Continuous Data: Colormaps
For heatmaps, density plots, geospatial fields — anywhere colour represents a continuous value.
Never use rainbow/jet
Do not build colormaps from brand colours. Use established perceptually uniform, CVD-safe colormaps:
| Data type | Recommended approach | Examples |
|---|---|---|
| Sequential (zero → max) | Perceptually uniform sequential map | viridiscividisbatlow |
| Diverging (meaningful midpoint) | Perceptually uniform diverging map | vikromaRdBu |
| Cyclic (phase / angle / time-of-day) | Cyclic map | twilightromaO |
viridis — sequential
RdBu — diverging
twilight — cyclic
Always show a colour bar
Greyscale check
viridis, cividis,
and batlow are; rainbow is not.4. Typography in Plots
Consistent font choices across all chart elements support readability and brand cohesion.
| Element | Font | Size (min) | Colour |
|---|---|---|---|
| Chart title | Space Grotesk, 600 | 16 px min | #000000 |
| Subtitle / caption | Switzer, 400 | 12 px min | #848484 |
| Axis & data labels | Switzer, 400 | 12 px min | #404040 |
| Direct series labels | Switzer, 500 | 12 px min | series colour ≥ 4.5:1 |
Caption contrast note
#848484 is 3.7:1 on white — acceptable for large text only.
Use #6b6b6b for small captions (below 18.66 px / 14 px bold).Print / PDF export
5. Accessibility Checklist for Charts
Adapted from the Government Analysis Function 'accessible charts' checklist. Before shipping a chart, verify all items below.
6. Implementation
Define the palette once per stack. Never hard-code hex values inside individual plots.
All chart colours are available as CSS custom properties and language-specific constants. Reference these tokens in every chart implementation rather than repeating hex values.
CSS / JS tokens
:root {
--chart-cat-1: #26235c;
--chart-cat-2: #73a235;
--chart-cat-3: #b34a00;
--chart-cat-4: #56b4e9;
--chart-cat-5: #cc79a7;
--chart-muted: #b8b8b8;
--chart-grid: #e5e5e5;
}
.dark {
--chart-cat-1: #8a94c9;
--chart-cat-2: #90ca42;
--chart-cat-3: #e07b39;
}Matplotlib (Python)
import matplotlib as mpl
SDSC_CATEGORICAL = ["#26235c", "#73a235", "#b34a00", "#56b4e9", "#cc79a7"]
mpl.rcParams.update({
"axes.prop_cycle": mpl.cycler(color=SDSC_CATEGORICAL),
"image.cmap": "viridis",
"axes.grid": True, "axes.grid.axis": "y",
"grid.color": "#e5e5e5", "axes.edgecolor": "#848484",
"axes.spines.top": False, "axes.spines.right": False,
"font.size": 12, "figure.dpi": 150,
})Plotly (Python / JS)
import plotly.io as pio
import plotly.graph_objects as go
pio.templates["sdsc"] = go.layout.Template(layout={
"colorway": ["#26235c", "#73a235", "#b34a00", "#56b4e9", "#cc79a7"],
"colorscale": {"sequential": "Viridis"},
"font": {"size": 12},
"xaxis": {"showgrid": False},
"yaxis": {"gridcolor": "#e5e5e5"},
"plot_bgcolor": "white",
})
pio.templates.default = "sdsc"Crameri colormaps
pip install cmcrameri (Python) or the scico package (R) provide the full Scientific colour
maps collection.7. References
Authoritative sources behind every recommendation in this document.

