Scales & Domains
Essential scale functions for mapping data values to visual properties.
Linear Scale
Basic Linear Scale
const xScale = d3
.scaleLinear()
.domain([0, 100]) // Input domain
.range([0, 500]); // Output range
console.log(xScale(50)); // 250
console.log(xScale(25)); // 125
Scale with Data
const data = [10, 50, 30, 80, 45];
const yScale = d3
.scaleLinear()
.domain(d3.extent(data)) // [10, 80]
.range([height, 0]); // Invert for SVG coordinates
// Or specify domain manually
const yScale2 = d3
.scaleLinear()
.domain([0, d3.max(data)])
.range([height, 0]);
Scale Methods
const scale = d3.scaleLinear().domain([0, 100]).range([0, 500]);
// Get scaled value
scale(50); // 250
// Invert (get domain value from range)
scale.invert(250); // 50
// Get nice domain
scale.nice(); // Rounds domain to nice values
// Clamp values to range
scale.clamp(true);
console.log(scale(150)); // 500 (clamped)
Band Scale (Categorical Data)
Basic Band Scale
const categories = ['A', 'B', 'C', 'D'];
const xScale = d3.scaleBand().domain(categories).range([0, 400]).padding(0.1);
console.log(xScale('B')); // Position of category B
console.log(xScale.bandwidth()); // Width of each band
console.log(xScale.step()); // Distance between band starts
Band Scale with Padding
const xScale = d3
.scaleBand()
.domain(categories)
.range([0, 400])
.padding(0.1) // Outer padding
.paddingInner(0.1) // Inner padding only
.paddingOuter(0.2); // Outer padding only
Ordinal Scale
Basic Ordinal Scale
const colorScale = d3
.scaleOrdinal()
.domain(['A', 'B', 'C'])
.range(['red', 'blue', 'green']);
console.log(colorScale('A')); // "red"
console.log(colorScale('B')); // "blue"
Built-in Color Schemes
// Category colors
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);
const darkColors = d3.scaleOrdinal(d3.schemeDark2);
// Set domain explicitly
colorScale.domain(['Apple', 'Orange', 'Banana']);
Time Scale
Basic Time Scale
const timeScale = d3
.scaleTime()
.domain([new Date(2020, 0, 1), new Date(2021, 0, 1)])
.range([0, 500]);
// Parse date strings first
const parseDate = d3.timeParse('%Y-%m-%d');
const dates = ['2020-01-01', '2020-06-01', '2020-12-31'];
const parsedDates = dates.map(parseDate);
const timeScale2 = d3
.scaleTime()
.domain(d3.extent(parsedDates))
.range([0, width]);
Time Scale with Nice Ticks
const timeScale = d3
.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width])
.nice(); // Round to nice time intervals
Color Scales
Sequential Color Scale
const colorScale = d3.scaleSequential(d3.interpolateBlues).domain([0, 100]);
console.log(colorScale(25)); // Light blue
console.log(colorScale(75)); // Dark blue
Diverging Color Scale
const colorScale = d3
.scaleDiverging(d3.interpolateRdYlBu)
.domain([-100, 0, 100]); // Negative, neutral, positive
Threshold Scale
const colorScale = d3
.scaleThreshold()
.domain([10, 20, 30])
.range(['red', 'orange', 'yellow', 'green']);
console.log(colorScale(5)); // "red"
console.log(colorScale(15)); // "orange"
console.log(colorScale(25)); // "yellow"
console.log(colorScale(35)); // "green"
Quantile and Quantize Scales
Quantile Scale
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const quantileScale = d3
.scaleQuantile()
.domain(data)
.range(['low', 'medium', 'high']);
console.log(quantileScale.quantiles()); // [3.67, 6.33]
Quantize Scale
const quantizeScale = d3
.scaleQuantize()
.domain([0, 100])
.range(['low', 'medium', 'high']);
console.log(quantizeScale(25)); // "low"
console.log(quantizeScale(50)); // "medium"
console.log(quantizeScale(75)); // "high"
Log and Power Scales
Log Scale
const logScale = d3.scaleLog().domain([1, 1000]).range([0, 500]).base(10); // Default is e, can specify base
Power Scale
const powerScale = d3.scalePow().domain([0, 100]).range([0, 500]).exponent(2); // Square scale
// Square root scale (shorthand)
const sqrtScale = d3.scaleSqrt().domain([0, 100]).range([0, 500]);
Scale Utilities
Creating Scales from Data
const data = [
{ x: 10, y: 20, category: 'A' },
{ x: 30, y: 40, category: 'B' },
{ x: 50, y: 60, category: 'C' },
];
// Scales from data extents
const xScale = d3
.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([0, width]);
const yScale = d3
.scaleLinear()
.domain(d3.extent(data, d => d.y))
.range([height, 0]);
const colorScale = d3
.scaleOrdinal(d3.schemeCategory10)
.domain([...new Set(data.map(d => d.category))]);
Scale Composition
// Combine scales for complex mappings
const radiusScale = d3
.scaleSqrt()
.domain([0, d3.max(data, d => d.value)])
.range([5, 30]);
const opacityScale = d3
.scaleLinear()
.domain(d3.extent(data, d => d.confidence))
.range([0.3, 1.0]);
Common Patterns
Margin Convention with Scales
const margin = { top: 20, right: 20, bottom: 30, left: 50 };
const width = 960 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
const xScale = d3
.scaleLinear()
.domain(d3.extent(data, d => d.x))
.range([0, width]); // Use inner width
const yScale = d3
.scaleLinear()
.domain(d3.extent(data, d => d.y))
.range([height, 0]); // Use inner height