Линейный масштаб: d3.scaleLinear()

D3.js предоставляет мощный набор инструментов для преобразования данных в визуальные представления, и одной из базовых концепций в этой библиотеке являются шкалы (scales). Шкала — это функция преобразования входных данных (domain) в визуальные значения (range). Линейная шкала, реализуемая через d3.scaleLinear(), является фундаментальным инструментом для работы с числовыми данными, где требуется пропорциональное отображение значений.


Линейная шкала устанавливает прямое соответствие между двумя числовыми диапазонами:

  • Domain (область входных значений) — исходные данные
  • Range (область выходных значений) — визуальные координаты, размеры, цвета и т.д.

Формально преобразование можно представить как линейную функцию:

genui{“math_block_widget_always_prefetch_v2”:{“content”:“y = ax + b”}}

где:

  • x — входное значение из domain
  • y — преобразованное значение в range
  • a и b вычисляются автоматически на основе заданных диапазонов

Создание линейной шкалы

Базовый синтаксис:

const scale = d3.scaleLinear();

После создания шкалу необходимо настроить:

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

В этом примере:

  • значение 0 соответствует 0
  • значение 100 соответствует 500
  • все промежуточные значения масштабируются линейно

Пример преобразования значений

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

console.log(scale(0));   // 0
console.log(scale(5));   // 50
console.log(scale(10));  // 100

Линейность означает сохранение пропорций между значениями.


Инверсия шкалы: scale.invert()

Линейная шкала поддерживает обратное преобразование:

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

console.log(scale.invert(50)); // 5

Это особенно важно при:

  • обработке событий мыши
  • вычислении значений по координатам
  • интерактивных графиках

Поведение вне диапазона (clamping)

По умолчанию шкала допускает выход за пределы domain:

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

console.log(scale(-5));  // -50
console.log(scale(15));  // 150

Чтобы ограничить значения, используется clamp:

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

console.log(scale(-5));  // 0
console.log(scale(15));  // 100

Нормализация значений внутри шкалы

Линейная шкала фактически выполняет нормализацию:

t =

и затем масштабирование:

y = r_{min} + t (r_{max} - r_{min})

где:

  • d_min, d_max — границы domain
  • r_min, r_max — границы range

Использование с осями (axis)

Линейные шкалы тесно связаны с осями:

const xScale = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 600]);

const xAxis = d3.axisBottom(xScale);

Шкала определяет:

  • положение делений
  • подписи
  • интервалы

ticks() и nice()

ticks()

Позволяет получить “красивые” значения для оси:

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

console.log(scale.ticks(5));

Результат будет приближен к удобным числам, например:

[0, 20, 40, 60, 80, 100]

nice()

Автоматически расширяет domain до округлых значений:

scale.nice();

Если было:

[3, 97]

может стать:

[0, 100]

Интерполяция значений

Линейная шкала не ограничена числами в range. Она может интерполировать любые типы:

const colorScale = d3.scaleLinear()
  .domain([0, 100])
  .range(["blue", "red"]);

Здесь происходит интерполяция цвета:

  • 0 → синий
  • 100 → красный
  • промежуточные значения → градиент

Обработка нечисловых входов

Если входное значение невозможно преобразовать в число, результат будет NaN:

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

console.log(scale("abc")); // NaN

Поэтому данные часто предварительно очищаются или приводятся к числовому виду.


Использование с графиками

Линейная шкала применяется при построении координатных систем:

const x = d3.scaleLinear()
  .domain([0, 100])
  .range([0, width]);

const y = d3.scaleLinear()
  .domain([0, 50])
  .range([height, 0]);

svg.selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", d => x(d.x))
  .attr("cy", d => y(d.y))
  .attr("r", 4);

Особенность:

  • ось Y инвертирована (height → 0), так как экранные координаты растут вниз

Вложенные и комбинированные преобразования

Линейные шкалы часто комбинируются:

const opacityScale = d3.scaleLinear()
  .domain([0, 100])
  .range([0, 1]);

const sizeScale = d3.scaleLinear()
  .domain([0, 100])
  .range([2, 20]);

Это позволяет управлять несколькими визуальными параметрами одновременно.


Производительность и поведение

Линейная шкала:

  • работает за O(1) для каждого вызова
  • не требует пересчёта при каждом использовании
  • кэширует вычисленные коэффициенты внутри

При изменении domain или range коэффициенты пересчитываются автоматически.


Типичные ошибки при использовании

  1. Перепутанный domain и range

    .domain([0, 500]).range([0, 100])

    приводит к неожиданному масштабу

  2. Инверсия оси без учета range

    • особенно важно для SVG координат
  3. Отсутствие обработки NaN

    • приводит к разрывам графика
  4. Использование строк вместо чисел

    • нарушает линейную интерполяцию

Роль в системе визуализации данных

Линейная шкала является базовым строительным блоком:

  • координатные системы
  • диаграммы рассеяния
  • линейные графики
  • тепловые карты (частично)
  • анимации изменений значений

Она обеспечивает строгую математическую связь между данными и визуальной формой, сохраняя пропорции и делая визуализацию интерпретируемой без дополнительных преобразований.