or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

continuous-scales.mddiscrete-scales.mddiverging-scales.mdindex.mdsequential-scales.mdutilities.md
tile.json

utilities.mddocs/

Utilities

d3-scale provides utility functions and constants that support scale operations, axis formatting, and scale behavior configuration.

Capabilities

Tick Formatting

Intelligent automatic formatting for numeric tick labels on axes and legends.

/**
 * Generate an appropriate number format for tick labels
 * @param start - Start of the domain range
 * @param stop - End of the domain range  
 * @param count - Approximate number of ticks
 * @param specifier - Optional d3-format specifier string
 * @returns Function that formats numbers for display
 */
function tickFormat(start: number, stop: number, count: number, specifier?: string): (n: number) => string;

The tickFormat function analyzes the numeric range and count to determine the most appropriate formatting, considering:

  • Decimal places needed for precision
  • Scientific notation for very large/small numbers
  • Thousands separators for readability
  • Percentage formatting when appropriate

Usage Examples:

import { tickFormat } from "d3-scale";

// Basic numeric formatting
const formatter1 = tickFormat(0, 100, 10);
console.log(formatter1(0));    // "0"
console.log(formatter1(50));   // "50" 
console.log(formatter1(100));  // "100"

// Decimal formatting for small ranges
const formatter2 = tickFormat(0, 1, 10);
console.log(formatter2(0.1));  // "0.1"
console.log(formatter2(0.25)); // "0.25"
console.log(formatter2(0.5));  // "0.5"

// Large number formatting
const formatter3 = tickFormat(0, 1000000, 5);
console.log(formatter3(0));      // "0"
console.log(formatter3(250000)); // "250k" or "250,000"
console.log(formatter3(1000000)); // "1M" or "1,000,000"

// Scientific notation for very large ranges
const formatter4 = tickFormat(0, 1e12, 10);
console.log(formatter4(1e11)); // "1e+11" or formatted appropriately

// Custom format specifier
const percentFormatter = tickFormat(0, 1, 10, "%");
console.log(percentFormatter(0.5)); // "50%"

const currencyFormatter = tickFormat(0, 1000, 10, "$,.0f");
console.log(currencyFormatter(500)); // "$500"

Scale Constants

Special symbols and constants used for scale behavior configuration.

/**
 * Symbol used with ordinal scales to indicate implicit domain expansion
 * When set as the unknown value, causes ordinal scales to automatically
 * add new domain values as they are encountered
 */
const scaleImplicit: symbol;

The scaleImplicit symbol enables ordinal scales to automatically expand their domain when encountering new values, rather than returning the unknown value.

Usage Examples:

import { scaleOrdinal, scaleImplicit } from "d3-scale";

// Ordinal scale with explicit domain
const explicitScale = scaleOrdinal()
  .domain(['A', 'B', 'C'])
  .range(['red', 'green', 'blue'])
  .unknown('gray');

console.log(explicitScale('A')); // 'red'
console.log(explicitScale('D')); // 'gray' (unknown value)
console.log(explicitScale.domain()); // ['A', 'B', 'C'] (unchanged)

// Ordinal scale with implicit domain expansion
const implicitScale = scaleOrdinal()
  .range(['red', 'green', 'blue'])
  .unknown(scaleImplicit);

console.log(implicitScale('A')); // 'red' (A added to domain)
console.log(implicitScale('B')); // 'green' (B added to domain)
console.log(implicitScale('D')); // 'red' (D added, cycles through range)
console.log(implicitScale.domain()); // ['A', 'B', 'D'] (auto-expanded)

// Practical use case: dynamic category assignment
const dynamicColorScale = scaleOrdinal()
  .range(['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd'])
  .unknown(scaleImplicit);

// Colors assigned automatically as new categories appear
const data = [
  { category: 'Electronics', value: 100 },
  { category: 'Books', value: 50 },
  { category: 'Clothing', value: 75 },
  { category: 'Electronics', value: 80 }, // Reuses existing color
  { category: 'Home & Garden', value: 60 } // New category, gets next color
];

data.forEach(d => {
  const color = dynamicColorScale(d.category);
  console.log(`${d.category}: ${color}`);
});

console.log(dynamicColorScale.domain()); // ['Electronics', 'Books', 'Clothing', 'Home & Garden']

Integration with Scale Methods

Tick Formatting with Scales

Most continuous scales provide their own tickFormat method that internally uses the utility function:

import { scaleLinear, tickFormat } from "d3-scale";

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

// Scale's built-in tick formatting
const scaleFormatter = scale.tickFormat(10);
console.log(scaleFormatter(50)); // Formatted using scale's knowledge

// Equivalent manual approach
const manualFormatter = tickFormat(0, 100, 10);
console.log(manualFormatter(50)); // Same result

// Custom specifier through scale
const customScaleFormatter = scale.tickFormat(10, ".1f");
console.log(customScaleFormatter(50)); // "50.0"

Time Scale Formatting

Time scales use specialized formatting but the principle is similar:

import { scaleTime } from "d3-scale";

const timeScale = scaleTime()
  .domain([new Date(2020, 0, 1), new Date(2023, 0, 1)])
  .range([0, 400]);

// Time-specific formatting
const timeFormatter = timeScale.tickFormat(5);
console.log(timeFormatter(new Date(2021, 6, 1))); // "Jul 2021" or similar

// Custom time format
const customTimeFormatter = timeScale.tickFormat(10, "%Y-%m");
console.log(customTimeFormatter(new Date(2021, 6, 1))); // "2021-07"

Common Utility Patterns

Axis Label Generation

Combine tick generation with formatting for complete axis solutions:

import { scaleLinear, tickFormat } from "d3-scale";

function generateAxisLabels(scale, tickCount = 10) {
  const ticks = scale.ticks(tickCount);
  const format = scale.tickFormat(tickCount);
  
  return ticks.map(tick => ({
    value: tick,
    position: scale(tick),
    label: format(tick)
  }));
}

const scale = scaleLinear().domain([0, 1000]).range([0, 400]);
const axisLabels = generateAxisLabels(scale, 5);

axisLabels.forEach(({ value, position, label }) => {
  console.log(`Value: ${value}, Position: ${position}, Label: "${label}"`);
});

Dynamic Range Detection

Use tick formatting to handle unknown data ranges:

import { tickFormat, extent } from "d3-scale";

function createSmartFormatter(data, tickCount = 10) {
  const [min, max] = extent(data);
  return tickFormat(min, max, tickCount);
}

// Adapts formatting to data range automatically
const dataset1 = [0.001, 0.005, 0.012, 0.028, 0.045];
const formatter1 = createSmartFormatter(dataset1);
console.log(formatter1(0.012)); // Appropriate decimal precision

const dataset2 = [1000, 5000, 12000, 28000, 45000];
const formatter2 = createSmartFormatter(dataset2);
console.log(formatter2(12000)); // Appropriate thousands formatting

Scale Debugging and Inspection

Utilities for inspecting scale behavior:

import { scaleOrdinal, scaleImplicit } from "d3-scale";

function inspectOrdinalScale(scale) {
  return {
    domain: scale.domain(),
    range: scale.range(),
    isImplicit: scale.unknown() === scaleImplicit,
    mappings: scale.domain().map(d => ({ input: d, output: scale(d) }))
  };
}

const scale = scaleOrdinal()
  .range(['red', 'green', 'blue'])
  .unknown(scaleImplicit);

// Test with some values
scale('A');
scale('B');
scale('C');
scale('D');

console.log(inspectOrdinalScale(scale));
// Shows complete scale state including auto-expanded domain

Type Definitions

type TickFormatter = (n: number) => string;