Files
antigravity-skills-reference/skills/claude-d3js-skill/references/scale-reference.md

12 KiB

D3.js Scale Reference

Comprehensive guide to all d3 scale types with examples and use cases.

Continuous scales

Linear scale

Maps continuous input domain to continuous output range with linear interpolation.

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 500]);

scale(50);  // Returns 250
scale(0);   // Returns 0
scale(100); // Returns 500

// Invert scale (get input from output)
scale.invert(250); // Returns 50

Use cases:

  • Most common scale for quantitative data
  • Axes, bar lengths, position encoding
  • Temperature, prices, counts, measurements

Methods:

  • .domain([min, max]) - Set input domain
  • .range([min, max]) - Set output range
  • .invert(value) - Get domain value from range value
  • .clamp(true) - Restrict output to range bounds
  • .nice() - Extend domain to nice round values

Power scale

Maps continuous input to continuous output with exponential transformation.

const sqrtScale = d3.scalePow()
  .exponent(0.5)  // Square root
  .domain([0, 100])
  .range([0, 500]);

const squareScale = d3.scalePow()
  .exponent(2)  // Square
  .domain([0, 100])
  .range([0, 500]);

// Shorthand for square root
const sqrtScale2 = d3.scaleSqrt()
  .domain([0, 100])
  .range([0, 500]);

Use cases:

  • Perceptual scaling (human perception is non-linear)
  • Area encoding (use square root to map values to circle radii)
  • Emphasising differences in small or large values

Logarithmic scale

Maps continuous input to continuous output with logarithmic transformation.

const logScale = d3.scaleLog()
  .domain([1, 1000])  // Must be positive
  .range([0, 500]);

logScale(1);    // Returns 0
logScale(10);   // Returns ~167
logScale(100);  // Returns ~333
logScale(1000); // Returns 500

Use cases:

  • Data spanning multiple orders of magnitude
  • Population, GDP, wealth distributions
  • Logarithmic axes
  • Exponential growth visualisations

Important: Domain values must be strictly positive (>0).

Time scale

Specialised linear scale for temporal data.

const timeScale = d3.scaleTime()
  .domain([new Date(2020, 0, 1), new Date(2024, 0, 1)])
  .range([0, 800]);

timeScale(new Date(2022, 0, 1)); // Returns 400

// Invert to get date
timeScale.invert(400); // Returns Date object for mid-2022

Use cases:

  • Time series visualisations
  • Timeline axes
  • Temporal animations
  • Date-based interactions

Methods:

  • .nice() - Extend domain to nice time intervals
  • .ticks(count) - Generate nicely-spaced tick values
  • All linear scale methods apply

Quantize scale

Maps continuous input to discrete output buckets.

const quantizeScale = d3.scaleQuantize()
  .domain([0, 100])
  .range(['low', 'medium', 'high']);

quantizeScale(25);  // Returns 'low'
quantizeScale(50);  // Returns 'medium'
quantizeScale(75);  // Returns 'high'

// Get the threshold values
quantizeScale.thresholds(); // Returns [33.33, 66.67]

Use cases:

  • Binning continuous data
  • Heat map colours
  • Risk categories (low/medium/high)
  • Age groups, income brackets

Quantile scale

Maps continuous input to discrete output based on quantiles.

const quantileScale = d3.scaleQuantile()
  .domain([3, 6, 7, 8, 8, 10, 13, 15, 16, 20, 24]) // Sample data
  .range(['low', 'medium', 'high']);

quantileScale(8);  // Returns based on quantile position
quantileScale.quantiles(); // Returns quantile thresholds

Use cases:

  • Equal-size groups regardless of distribution
  • Percentile-based categorisation
  • Handling skewed distributions

Threshold scale

Maps continuous input to discrete output with custom thresholds.

const thresholdScale = d3.scaleThreshold()
  .domain([0, 10, 20])
  .range(['freezing', 'cold', 'warm', 'hot']);

thresholdScale(-5);  // Returns 'freezing'
thresholdScale(5);   // Returns 'cold'
thresholdScale(15);  // Returns 'warm'
thresholdScale(25);  // Returns 'hot'

Use cases:

  • Custom breakpoints
  • Grade boundaries (A, B, C, D, F)
  • Temperature categories
  • Air quality indices

Sequential scales

Sequential colour scale

Maps continuous input to continuous colour gradient.

const colourScale = d3.scaleSequential(d3.interpolateBlues)
  .domain([0, 100]);

colourScale(0);   // Returns lightest blue
colourScale(50);  // Returns mid blue
colourScale(100); // Returns darkest blue

Available interpolators:

Single hue:

  • d3.interpolateBlues, d3.interpolateGreens, d3.interpolateReds
  • d3.interpolateOranges, d3.interpolatePurples, d3.interpolateGreys

Multi-hue:

  • d3.interpolateViridis, d3.interpolateInferno, d3.interpolateMagma
  • d3.interpolatePlasma, d3.interpolateWarm, d3.interpolateCool
  • d3.interpolateCubehelixDefault, d3.interpolateTurbo

Use cases:

  • Heat maps, choropleth maps
  • Continuous data visualisation
  • Temperature, elevation, density

Diverging colour scale

Maps continuous input to diverging colour gradient with a midpoint.

const divergingScale = d3.scaleDiverging(d3.interpolateRdBu)
  .domain([-10, 0, 10]);

divergingScale(-10); // Returns red
divergingScale(0);   // Returns white/neutral
divergingScale(10);  // Returns blue

Available interpolators:

  • d3.interpolateRdBu - Red to blue
  • d3.interpolateRdYlBu - Red, yellow, blue
  • d3.interpolateRdYlGn - Red, yellow, green
  • d3.interpolatePiYG - Pink, yellow, green
  • d3.interpolateBrBG - Brown, blue-green
  • d3.interpolatePRGn - Purple, green
  • d3.interpolatePuOr - Purple, orange
  • d3.interpolateRdGy - Red, grey
  • d3.interpolateSpectral - Rainbow spectrum

Use cases:

  • Data with meaningful midpoint (zero, average, neutral)
  • Positive/negative values
  • Above/below comparisons
  • Correlation matrices

Sequential quantile scale

Combines sequential colour with quantile mapping.

const sequentialQuantileScale = d3.scaleSequentialQuantile(d3.interpolateBlues)
  .domain([3, 6, 7, 8, 8, 10, 13, 15, 16, 20, 24]);

// Maps based on quantile position

Use cases:

  • Perceptually uniform binning
  • Handling outliers
  • Skewed distributions

Ordinal scales

Band scale

Maps discrete input to continuous bands (rectangles) with optional padding.

const bandScale = d3.scaleBand()
  .domain(['A', 'B', 'C', 'D'])
  .range([0, 400])
  .padding(0.1);

bandScale('A');           // Returns start position (e.g., 0)
bandScale('B');           // Returns start position (e.g., 110)
bandScale.bandwidth();    // Returns width of each band (e.g., 95)
bandScale.step();         // Returns total step including padding
bandScale.paddingInner(); // Returns inner padding (between bands)
bandScale.paddingOuter(); // Returns outer padding (at edges)

Use cases:

  • Bar charts (most common use case)
  • Grouped elements
  • Categorical axes
  • Heat map cells

Padding options:

  • .padding(value) - Sets both inner and outer padding (0-1)
  • .paddingInner(value) - Padding between bands (0-1)
  • .paddingOuter(value) - Padding at edges (0-1)
  • .align(value) - Alignment of bands (0-1, default 0.5)

Point scale

Maps discrete input to continuous points (no width).

const pointScale = d3.scalePoint()
  .domain(['A', 'B', 'C', 'D'])
  .range([0, 400])
  .padding(0.5);

pointScale('A'); // Returns position (e.g., 50)
pointScale('B'); // Returns position (e.g., 150)
pointScale('C'); // Returns position (e.g., 250)
pointScale('D'); // Returns position (e.g., 350)
pointScale.step(); // Returns distance between points

Use cases:

  • Line chart categorical x-axis
  • Scatter plot with categorical axis
  • Node positions in network graphs
  • Any point positioning for categories

Ordinal colour scale

Maps discrete input to discrete output (colours, shapes, etc.).

const colourScale = d3.scaleOrdinal(d3.schemeCategory10);

colourScale('apples');  // Returns first colour
colourScale('oranges'); // Returns second colour
colourScale('apples');  // Returns same first colour (consistent)

// Custom range
const customScale = d3.scaleOrdinal()
  .domain(['cat1', 'cat2', 'cat3'])
  .range(['#FF6B6B', '#4ECDC4', '#45B7D1']);

Built-in colour schemes:

Categorical:

  • d3.schemeCategory10 - 10 colours
  • d3.schemeAccent - 8 colours
  • d3.schemeDark2 - 8 colours
  • d3.schemePaired - 12 colours
  • d3.schemePastel1 - 9 colours
  • d3.schemePastel2 - 8 colours
  • d3.schemeSet1 - 9 colours
  • d3.schemeSet2 - 8 colours
  • d3.schemeSet3 - 12 colours
  • d3.schemeTableau10 - 10 colours

Use cases:

  • Category colours
  • Legend items
  • Multi-series charts
  • Network node types

Scale utilities

Nice domain

Extend domain to nice round values.

const scale = d3.scaleLinear()
  .domain([0.201, 0.996])
  .nice();

scale.domain(); // Returns [0.2, 1.0]

// With count (approximate tick count)
const scale2 = d3.scaleLinear()
  .domain([0.201, 0.996])
  .nice(5);

Clamping

Restrict output to range bounds.

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 500])
  .clamp(true);

scale(-10); // Returns 0 (clamped)
scale(150); // Returns 500 (clamped)

Copy scales

Create independent copies.

const scale1 = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 500]);

const scale2 = scale1.copy();
// scale2 is independent of scale1

Tick generation

Generate nice tick values for axes.

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 500]);

scale.ticks(10);        // Generate ~10 ticks
scale.tickFormat(10);   // Get format function for ticks
scale.tickFormat(10, ".2f"); // Custom format (2 decimal places)

// Time scale ticks
const timeScale = d3.scaleTime()
  .domain([new Date(2020, 0, 1), new Date(2024, 0, 1)]);

timeScale.ticks(d3.timeYear);      // Yearly ticks
timeScale.ticks(d3.timeMonth, 3);  // Every 3 months
timeScale.tickFormat(5, "%Y-%m");  // Format as year-month

Colour spaces and interpolation

RGB interpolation

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range(["blue", "red"]);
// Default: RGB interpolation

HSL interpolation

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range(["blue", "red"])
  .interpolate(d3.interpolateHsl);
// Smoother colour transitions

Lab interpolation

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range(["blue", "red"])
  .interpolate(d3.interpolateLab);
// Perceptually uniform

HCL interpolation

const scale = d3.scaleLinear()
  .domain([0, 100])
  .range(["blue", "red"])
  .interpolate(d3.interpolateHcl);
// Perceptually uniform with hue

Common patterns

Diverging scale with custom midpoint

const scale = d3.scaleLinear()
  .domain([min, midpoint, max])
  .range(["red", "white", "blue"])
  .interpolate(d3.interpolateHcl);

Multi-stop gradient scale

const scale = d3.scaleLinear()
  .domain([0, 25, 50, 75, 100])
  .range(["#d53e4f", "#fc8d59", "#fee08b", "#e6f598", "#66c2a5"]);

Radius scale for circles (perceptual)

const radiusScale = d3.scaleSqrt()
  .domain([0, d3.max(data, d => d.value)])
  .range([0, 50]);

// Use with circles
circle.attr("r", d => radiusScale(d.value));

Adaptive scale based on data range

function createAdaptiveScale(data) {
  const extent = d3.extent(data);
  const range = extent[1] - extent[0];
  
  // Use log scale if data spans >2 orders of magnitude
  if (extent[1] / extent[0] > 100) {
    return d3.scaleLog()
      .domain(extent)
      .range([0, width]);
  }
  
  // Otherwise use linear
  return d3.scaleLinear()
    .domain(extent)
    .range([0, width]);
}

Colour scale with explicit categories

const colourScale = d3.scaleOrdinal()
  .domain(['Low Risk', 'Medium Risk', 'High Risk'])
  .range(['#2ecc71', '#f39c12', '#e74c3c'])
  .unknown('#95a5a6'); // Fallback for unknown values