Что такое масштаб в D3: домен и диапазон

Масштабирование в D3.js представляет собой механизм преобразования значений из одной числовой или категориальной области в другую. Это фундаментальный слой абстракции, который связывает данные с визуальным представлением. Любая визуализация — ось, диаграмма, точка на графике или длина столбца — опирается на функцию масштаба, которая определяет соответствие между исходными данными и экранными координатами.

Ключевая идея масштаба выражается двумя понятиями: домен и диапазон.


Домен (domain)

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

Формально домен отвечает на вопрос:

какие значения данных мы преобразуем?

Пример:

d3.scaleLinear()
  .domain([0, 100])

В этом случае доменом являются значения от 0 до 100. Любое входное значение масштаба будет интерпретироваться относительно этих границ.

Особенности домена:

  • Может быть непрерывным (например, числа)
  • Может быть дискретным (категории)
  • Может задаваться вручную или вычисляться автоматически через d3.extent
  • Определяет «входную шкалу» данных

Пример автоматического вычисления:

const data = [10, 25, 37, 80];

const scale = d3.scaleLinear()
  .domain(d3.extent(data))

d3.extent возвращает минимальное и максимальное значение массива, формируя домен автоматически.


Диапазон (range)

Диапазон — это пространство отображения. Он определяет, в какие значения будут преобразованы данные после применения масштаба.

Диапазон отвечает на вопрос:

куда мы отображаем данные?

В контексте визуализации это чаще всего:

  • пиксели на экране
  • углы
  • размеры
  • координаты SVG или Canvas

Пример:

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

Здесь значение 0 будет соответствовать 0 пикселям, а 100 — 500 пикселям.

Особенности диапазона:

  • Часто выражается в пикселях
  • Может быть инвертирован
  • Может выходить за пределы экрана (для анимаций и трансформаций)
  • Определяет «выходное пространство» визуализации

Линейное соответствие между доменом и диапазоном

Масштаб в D3 по умолчанию выполняет линейную интерполяцию.

Если задано:

.domain([a, b])
.range([c, d])

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

[ f(x) = c + (d - c)]

Это означает, что значение внутри домена пропорционально отображается в диапазон.

Пример:

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

scale(5); // 50

Инверсия диапазона

Диапазон может быть задан в обратном порядке:

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

В этом случае происходит инвертированное отображение: большие значения данных оказываются ближе к нулевой координате SVG.

Пример использования:

  • ось Y в SVG направлена сверху вниз
  • поэтому часто используют обратный диапазон для корректного отображения графиков

Влияние масштаба на визуализацию

Каждая геометрическая сущность в D3 зависит от масштаба:

  • координаты точек
  • высота столбцов
  • радиусы кругов
  • длины линий
  • положение осей

Пример столбчатой диаграммы:

const xScale = d3.scaleBand()
  .domain(["A", "B", "C"])
  .range([0, 300]);

const yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([200, 0]);

Здесь:

  • xScale распределяет категории по оси X
  • yScale преобразует числовые значения в высоту столбцов

Нормализация данных через масштаб

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

Пример:

const scale = d3.scaleLinear()
  .domain([200, 800])
  .range([0, 1]);

Теперь любое значение из диапазона 200–800 будет преобразовано в интервал 0–1.

Такой подход используется:

  • в анимациях
  • в градиентах
  • в интерполяции цветов
  • в вычислении прозрачности

Масштаб и интерполяция

При преобразовании значений D3 использует интерполяцию. Она зависит от типа масштаба:

  • линейная (scaleLinear)
  • логарифмическая (scaleLog)
  • степенная (scalePow)
  • временная (scaleTime)
  • порядковая (scaleBand, scalePoint)

Несмотря на различия, концепция домена и диапазона сохраняется во всех типах.

Пример логарифмического масштаба:

d3.scaleLog()
  .domain([1, 1000])
  .range([0, 300]);

Здесь расстояния между значениями растягиваются нелинейно, но принцип отображения «домен → диапазон» остаётся неизменным.


Масштаб и координатные системы SVG

SVG использует координаты, где:

  • (0, 0) находится в левом верхнем углу
  • ось Y направлена вниз

Это создаёт необходимость в трансформации диапазона:

const yScale = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);

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


Дискретный домен и категориальные масштабы

Не все данные являются числовыми. Для категорий используется дискретный домен.

d3.scaleBand()
  .domain(["Jan", "Feb", "Mar"])
  .range([0, 300]);

Здесь:

  • домен состоит из строковых значений
  • диапазон распределяет их равномерно по пространству

Каждая категория получает свой «отрезок» диапазона.


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

Масштаб в D3 — это функция, но также объект с состоянием. Он хранит:

  • домен
  • диапазон
  • параметры интерполяции
  • правила округления

Каждый вызов:

scale(value)

приводит к:

  1. нормализации значения относительно домена
  2. интерполяции в диапазоне
  3. возврату результирующего значения

Обратное преобразование (invert)

Некоторые масштабы поддерживают обратное преобразование:

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

scale.invert(250); // 50

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

Применение:

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

Взаимосвязь домена и диапазона как системы координат

Домен и диапазон образуют две взаимосвязанные системы:

  • домен — пространство данных
  • диапазон — пространство отображения

Масштаб выполняет роль функции перехода между ними:

данные → визуализация

Любое изменение домена или диапазона мгновенно меняет всю визуальную структуру, не затрагивая сами данные.