Data Visualization Color Guide

8 min readUpdated 2026-06-10

Here's a brutal truth: most dashboards are unreadable. Not because the data is complex, but because someone picked 12 random colors from a default palette and called it a day. When your line chart has six series and they're all mid-saturation blues and greens, nobody can tell which line is revenue and which is churn.

Data visualization color isn't about making charts "pretty." It's about encoding information. Every hue, every lightness shift, every saturation change should mean something. Get this right and your dashboards tell stories at a glance. Get it wrong and you've built expensive confusion.

I'm going to walk you through how companies like The New York Times, Stripe, and Observable build color systems for data — the rules they follow, the mistakes they avoid, and the code you can steal.

How It Works

The New York Times graphics team uses a custom sequential palette where lightness changes linearly but hue shifts slightly from yellow to red. This dual-encoding (lightness + hue) makes their choropleth maps readable even in grayscale print editions. Their COVID-19 maps used a 7-step sequential scale from light yellow (#FFFFCC) to dark red (#800026) — each step represents roughly equal perceptual distance in CIELAB space.

Stripe's Dashboard uses exactly 6 categorical colors for their revenue charts, each chosen to maintain a minimum deltaE of 30 in CIELAB color space between any two adjacent colors. This guarantees that even users with deuteranomaly (the most common form of color blindness, affecting 6% of males) can distinguish every data series. Their palette: #635BFF (violet), #00D4AA (teal), #FF6B6B (coral), #FFBB00 (amber), #0073E6 (blue), #A855F7 (purple).

Observable Plot (by Mike Bostock, creator of D3.js) defaults to a categorical palette derived from Tableau 10 but with improved perceptual uniformity. Their research showed that the original Tableau 10 had a 40% discrimination failure rate for deuteranopes on two of its color pairs. The revised version fixes this by shifting green toward teal and orange toward coral.

Spotify Wrapped uses gradient-based data visualization where values map to positions on a gradient rather than discrete colors. This allows them to show continuous data (listening minutes over a year) without the banding artifacts that discrete palettes create. The technique works because human vision perceives smooth color transitions as continuous data intuitively.

Google Analytics 4 made a controversial decision to limit their chart palette to just 4 distinct colors, using opacity variations (100%, 70%, 40%) for additional series. This "opacity stacking" approach reduces cognitive load because users only need to learn 4 hues, then interpret darkness as "more of the same thing."

How It Works

The New York Times graphics team uses a custom sequential palette where lightness changes linearly but hue shifts slightly from yellow to red. This dual-encoding (lightness + hue) makes their choropleth maps readable even in grayscale print editions. Their COVID-19 maps used a 7-step sequential scale from light yellow (#FFFFCC) to dark red (#800026) — each step represents roughly equal perceptual distance in CIELAB space.

Stripe's Dashboard uses exactly 6 categorical colors for their revenue charts, each chosen to maintain a minimum deltaE of 30 in CIELAB color space between any two adjacent colors. This guarantees that even users with deuteranomaly (the most common form of color blindness, affecting 6% of males) can distinguish every data series. Their palette: #635BFF (violet), #00D4AA (teal), #FF6B6B (coral), #FFBB00 (amber), #0073E6 (blue), #A855F7 (purple).

Observable Plot (by Mike Bostock, creator of D3.js) defaults to a categorical palette derived from Tableau 10 but with improved perceptual uniformity. Their research showed that the original Tableau 10 had a 40% discrimination failure rate for deuteranopes on two of its color pairs. The revised version fixes this by shifting green toward teal and orange toward coral.

Spotify Wrapped uses gradient-based data visualization where values map to positions on a gradient rather than discrete colors. This allows them to show continuous data (listening minutes over a year) without the banding artifacts that discrete palettes create. The technique works because human vision perceives smooth color transitions as continuous data intuitively.

Google Analytics 4 made a controversial decision to limit their chart palette to just 4 distinct colors, using opacity variations (100%, 70%, 40%) for additional series. This "opacity stacking" approach reduces cognitive load because users only need to learn 4 hues, then interpret darkness as "more of the same thing."

Real-World Examples

The New York Times graphics team uses a custom sequential palette where lightness changes linearly but hue shifts slightly from yellow to red. This dual-encoding (lightness + hue) makes their choropleth maps readable even in grayscale print editions. Their COVID-19 maps used a 7-step sequential scale from light yellow (#FFFFCC) to dark red (#800026) — each step represents roughly equal perceptual distance in CIELAB space.

Stripe's Dashboard uses exactly 6 categorical colors for their revenue charts, each chosen to maintain a minimum deltaE of 30 in CIELAB color space between any two adjacent colors. This guarantees that even users with deuteranomaly (the most common form of color blindness, affecting 6% of males) can distinguish every data series. Their palette: #635BFF (violet), #00D4AA (teal), #FF6B6B (coral), #FFBB00 (amber), #0073E6 (blue), #A855F7 (purple).

Observable Plot (by Mike Bostock, creator of D3.js) defaults to a categorical palette derived from Tableau 10 but with improved perceptual uniformity. Their research showed that the original Tableau 10 had a 40% discrimination failure rate for deuteranopes on two of its color pairs. The revised version fixes this by shifting green toward teal and orange toward coral.

Spotify Wrapped uses gradient-based data visualization where values map to positions on a gradient rather than discrete colors. This allows them to show continuous data (listening minutes over a year) without the banding artifacts that discrete palettes create. The technique works because human vision perceives smooth color transitions as continuous data intuitively.

Google Analytics 4 made a controversial decision to limit their chart palette to just 4 distinct colors, using opacity variations (100%, 70%, 40%) for additional series. This "opacity stacking" approach reduces cognitive load because users only need to learn 4 hues, then interpret darkness as "more of the same thing."

Generate a perceptually uniform sequential palette

// Using OKLCH for perceptually uniform data viz palettes
// Each step has equal visual distance
function sequentialPalette(
  startHue: number,
  endHue: number,
  steps: number = 7
): string[] {
  const palette: string[] = [];
  for (let i = 0; i < steps; i++) {
    const t = i / (steps - 1);
    // Lightness: 0.92 (light) to 0.35 (dark)
    const l = 0.92 - t * 0.57;
    // Chroma: low at extremes, peaks in middle
    const c = 0.08 + Math.sin(t * Math.PI) * 0.12;
    // Hue interpolation
    const h = startHue + t * (endHue - startHue);
    palette.push(`oklch(${l.toFixed(3)} ${c.toFixed(3)} ${h.toFixed(1)})`);
  }
  return palette;
}

// Categorical palette with guaranteed deltaE > 30
const categoricalColors = [
  'oklch(0.55 0.20 265)',  // violet
  'oklch(0.72 0.18 172)',  // teal
  'oklch(0.65 0.20 25)',   // coral
  'oklch(0.78 0.16 85)',   // amber
  'oklch(0.58 0.19 240)',  // blue
  'oklch(0.62 0.22 320)',  // magenta
];

// Diverging palette (negative → neutral → positive)
function divergingPalette(steps: number = 9): string[] {
  const mid = Math.floor(steps / 2);
  return Array.from({ length: steps }, (_, i) => {
    const t = (i - mid) / mid; // -1 to 1
    const l = 0.92 - Math.abs(t) * 0.45;
    const c = Math.abs(t) * 0.18;
    const h = t < 0 ? 25 : 265; // red → blue
    return `oklch(${l.toFixed(3)} ${c.toFixed(3)} ${h})`;
  });
}

Copy and paste into your project — free to use.

Testing & Standards

The New York Times graphics team uses a custom sequential palette where lightness changes linearly but hue shifts slightly from yellow to red. This dual-encoding (lightness + hue) makes their choropleth maps readable even in grayscale print editions. Their COVID-19 maps used a 7-step sequential scale from light yellow (#FFFFCC) to dark red (#800026) — each step represents roughly equal perceptual distance in CIELAB space.

Stripe's Dashboard uses exactly 6 categorical colors for their revenue charts, each chosen to maintain a minimum deltaE of 30 in CIELAB color space between any two adjacent colors. This guarantees that even users with deuteranomaly (the most common form of color blindness, affecting 6% of males) can distinguish every data series. Their palette: #635BFF (violet), #00D4AA (teal), #FF6B6B (coral), #FFBB00 (amber), #0073E6 (blue), #A855F7 (purple).

Observable Plot (by Mike Bostock, creator of D3.js) defaults to a categorical palette derived from Tableau 10 but with improved perceptual uniformity. Their research showed that the original Tableau 10 had a 40% discrimination failure rate for deuteranopes on two of its color pairs. The revised version fixes this by shifting green toward teal and orange toward coral.

Spotify Wrapped uses gradient-based data visualization where values map to positions on a gradient rather than discrete colors. This allows them to show continuous data (listening minutes over a year) without the banding artifacts that discrete palettes create. The technique works because human vision perceives smooth color transitions as continuous data intuitively.

Google Analytics 4 made a controversial decision to limit their chart palette to just 4 distinct colors, using opacity variations (100%, 70%, 40%) for additional series. This "opacity stacking" approach reduces cognitive load because users only need to learn 4 hues, then interpret darkness as "more of the same thing."

Pro Tips

Developer Perspective

The New York Times graphics team uses a custom sequential palette where lightness changes linearly but hue shifts slightly from yellow to red. This dual-encoding (lightness + hue) makes their choropleth maps readable even in grayscale print editions. Their COVID-19 maps used a 7-step sequential scale from light yellow (#FFFFCC) to dark red (#800026) — each step represents roughly equal perceptual distance in CIELAB space.

Stripe's Dashboard uses exactly 6 categorical colors for their revenue charts, each chosen to maintain a minimum deltaE of 30 in CIELAB color space between any two adjacent colors. This guarantees that even users with deuteranomaly (the most common form of color blindness, affecting 6% of males) can distinguish every data series. Their palette: #635BFF (violet), #00D4AA (teal), #FF6B6B (coral), #FFBB00 (amber), #0073E6 (blue), #A855F7 (purple).

Observable Plot (by Mike Bostock, creator of D3.js) defaults to a categorical palette derived from Tableau 10 but with improved perceptual uniformity. Their research showed that the original Tableau 10 had a 40% discrimination failure rate for deuteranopes on two of its color pairs. The revised version fixes this by shifting green toward teal and orange toward coral.

Spotify Wrapped uses gradient-based data visualization where values map to positions on a gradient rather than discrete colors. This allows them to show continuous data (listening minutes over a year) without the banding artifacts that discrete palettes create. The technique works because human vision perceives smooth color transitions as continuous data intuitively.

Google Analytics 4 made a controversial decision to limit their chart palette to just 4 distinct colors, using opacity variations (100%, 70%, 40%) for additional series. This "opacity stacking" approach reduces cognitive load because users only need to learn 4 hues, then interpret darkness as "more of the same thing."

Never use rainbow palettes for sequential data. The human eye perceives yellow as brighter than blue even at the same lightness value, creating false peaks in your data. Use single-hue or bi-hue sequential scales instead.

Limit categorical palettes to 6-8 colors maximum. Beyond 8 distinct colors, human ability to map 'which color means what' drops below 50% accuracy (research by Healey, 1996). If you need more categories, use small multiples instead.

Try It Yourself

Use these free tools to apply what you learned: