Why this matters
As a Data Visualization Engineer, your charts guide decisions. If colors don’t contrast enough, people with low vision or color vision deficiencies (CVD) can’t read labels, lines, or categories. Good contrast and safe palettes ensure everyone can read your dashboards, screenshots, printed reports, and presentations, in light and dark themes.
- Dashboards: Ensure chart lines, bars, annotations, and legends meet non-text contrast so trends are readable at a glance.
- Reports/Slides: Text over colored backgrounds must meet text contrast thresholds to be legible when printed or projected.
- Design Systems: Define a small set of reliable, accessible colors so teams reuse them consistently.
Concept explained simply
Color contrast is how different two colors appear in brightness. The more contrast, the easier they are to tell apart. Safe palettes are color sets designed to be distinguishable for people with CVD and to meet contrast thresholds against the background.
Mental model
- Signal vs. noise: Data marks (signal) must stand out from background and each other.
- Redundant encoding: Don’t rely on color alone. Add line styles, markers, text labels, or patterns.
- Two checks, always: 1) Contrast against background. 2) Distinguishability between categories.
Key thresholds you should remember
- Normal text: at least 4.5:1 contrast against its background.
- Large text (18 pt normal or 14 pt bold): at least 3:1.
- Non-text elements (chart lines, bars, icons, legend keys, focus outlines): at least 3:1 against the adjacent background.
- Preferred when feasible: 7:1 for excellent readability.
Show the contrast math (simple)
Contrast ratio uses relative luminance (L) from 0 (black) to 1 (white).
- Convert hex to sRGB (0–1), then linearize each channel: if s ≤ 0.03928 then s/12.92 else ((s + 0.055)/1.055)^2.4.
- Compute luminance: L = 0.2126 R + 0.7152 G + 0.0722 B.
- Contrast ratio: (Llighter + 0.05) / (Ldarker + 0.05).
Example: #1A73E8 on white yields ≈ 4.3:1 (borderline for normal text, fine for non-text).
A simple workflow to pick a safe palette
- Start with your background (light or dark) and decide the minimum: 3:1 for non-text, 4.5:1 for text.
- Choose 4–8 categorical hues that differ clearly (blue, orange, purple, teal, brown, magenta). Avoid relying on red vs green alone.
- Darken or desaturate bright colors until each color has ≥ 3:1 against the background.
- Add redundant encoding: line dashes, markers, textures, direct labels.
- Test grayscale. If categories collapse, adjust luminance spacing (make some darker/lighter).
- Check common CVD simulations mentally: ensure adjacent categories differ by hue and lightness, not just hue.
Quick palette templates you can start with
Light backgrounds (white/near-white):
- Categorical (5): #005A9C (blue), #A05A00 (dark orange), #2E7D32 (green), #6A1B9A (purple), #8E1B5B (magenta)
- Sequential (5, dark-to-light): #133A5E, #1F5A8A, #357ABD, #70A6D8, #C9DEFF
- Diverging (7, center at zero): #6A1B9A, #8E44AD, #BDC3C7 (neutral), #E67E22, #A04000, plus deeper ends #4A148C and #A83200
Dark backgrounds (charcoal/navy):
- Categorical (5): #9CCAFF (light blue), #FFD089 (amber), #9DE2C1 (mint), #D1A6FF (lavender), #FF9AC2 (pink)
- Tip: Ensure text on colored chips is high contrast (often white text needs 4.5:1 against the chip color).
Worked examples
Example 1: 4-line time series on white
- Pick colors: #005A9C (solid), #A05A00 (dash), #2E7D32 (dot), #6A1B9A (dash-dot). All have ≥ 3:1 against white.
- Ensure 2–3 px stroke for visibility; add markers for peak points.
- Use 12–14 px axis labels in #111827 (near-black) for ≥ 10:1 contrast.
Why this works
Each line has luminance separation and a unique line style. Even in grayscale or with CVD, users can track series via dashes/markers.
Example 2: Diverging heatmap around zero
- Set center (0) to near-neutral (#ECEFF1 on white) so small values don’t pop.
- Negative side: deep purple to mid-violet (#4A148C → #8E44AD).
- Positive side: deep burnt orange to mid-orange (#A04000 → #E67E22).
- Annotate extreme cells with bold text that meets 4.5:1 against the cell color (use black text on light cells, white text on dark cells).
Why this works
The neutral center reduces false emphasis. Ends are distinguishable in both hue and luminance.
Example 3: Replacing red/green categories
- Avoid pure red vs green as the only distinction.
- Use #005A9C (blue) and #A05A00 (dark orange) instead, or keep red/green but add shape/pattern and adjust lightness so one is darker.
- Ensure ≥ 3:1 vs background and clear difference in lightness between categories.
Why this works
Many users with deuteranopia struggle with red/green separation. Hue + lightness + pattern ensures robust recognition.
Hands-on exercises
Match these with the exercises below to check your work.
- Contrast checks: Compute ratios and pass/fail for text and chart elements (pairs provided).
- Create a 5-color safe palette: Propose hex values that meet ≥ 3:1 on white, and specify how you’ll add redundant encoding.
- [ ] I verified text contrast ≥ 4.5:1.
- [ ] I verified non-text contrast ≥ 3:1.
- [ ] My palette remains usable in grayscale.
- [ ] I added dashes/markers/patterns as backups.
Common mistakes and how to self-check
- Relying on hue only: If two colors look identical in grayscale, add lightness contrast or patterns.
- Pastels on white: Often fail 3:1. Darken until ≥ 3:1 for lines/fills.
- Tiny text on color chips: 10–12 px text usually needs very dark chips or near-white text with ≥ 4.5:1.
- Forgetting dark mode: What passes on white may fail on charcoal; invert your lightness logic.
- Overusing red/green: Swap one hue or add a pattern/dash; ensure luminance separation.
Self-check routine
- Check each color’s contrast to background (aim ≥ 3:1 for non-text; text ≥ 4.5:1).
- Desaturate the figure; confirm categories remain separable.
- Scan at 50% zoom; if it’s still readable, it’s robust.
Practical projects
- Dashboard makeover: Take an existing dashboard with low-contrast colors. Replace with a 5-color safe palette, add redundant encodings, and document before/after contrast ratios.
- Heatmap redesign: Build a diverging heatmap for a metric centered at zero. Ensure cell labels meet text contrast against varying cell colors.
- Dark-mode theme: Create light and dark variants of a palette. Provide rules for when to switch label color to white or near-black.
Who this is for
Data Visualization Engineers, BI Developers, Analytics Engineers, and Designers who publish dashboards or reports that must be readable by all audiences.
Prerequisites
- Basic understanding of charts (line, bar, heatmap, scatter).
- Familiarity with CSS/hex colors or your BI tool’s color editor.
- Willingness to iterate with simple checks (contrast and grayscale).
Learning path
- Learn contrast basics and thresholds.
- Build a small safe palette for your default background.
- Add redundant encodings to line/scatter charts.
- Design a diverging scale for metrics with a meaningful midpoint.
- Create a dark-mode variant.
Mini challenge
Pick any chart you made recently. In 15 minutes, improve its accessibility: ensure lines/bars meet ≥ 3:1 against background, labels are ≥ 4.5:1, and at least one redundant encoding is added. Save a before/after image and note what changed.
Quick Test
Take the quick test below to lock in the concepts. Available to everyone; sign in to save your progress for later review.