d3.bin(): построение гистограмм из сырых данных

Работа с сырыми числовыми данными часто требует преобразования их в распределение частот. Для этого в D3.js используется генератор бинов, реализованный через d3.bin. Он преобразует массив значений в набор интервалов, где каждый интервал содержит элементы исходного массива, попавшие в заданный диапазон.

Биннинг представляет собой форму дискретизации непрерывной шкалы. В результате формируется структура данных, удобная для построения гистограмм, анализа распределений и визуального выявления плотностей.


Создание генератора бинов

Функция d3.bin() возвращает генератор, который настраивается через цепочку методов и затем применяется к массиву данных.

const bin = d3.bin();

После создания объект не содержит пользовательских настроек и использует значения по умолчанию:

  • диапазон определяется автоматически по данным;
  • количество интервалов вычисляется эвристически;
  • доступ к значению осуществляется как d => d.

Основной принцип работы биннинга

Алгоритм выполняет три ключевых шага:

  1. Определение числового диапазона данных.
  2. Разбиение диапазона на интервалы (bins).
  3. Распределение элементов массива по этим интервалам.

Каждый бин представляет собой массив исходных значений и содержит дополнительные свойства:

  • x0 — левая граница интервала;
  • x1 — правая граница интервала.

Доступ к значению (value accessor)

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

const bin = d3.bin()
  .value(d => d.price);

В этом случае биннинг выполняется по полю price, а не по самому объекту.


Настройка диапазона (domain)

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

const bin = d3.bin()
  .domain([0, 100]);

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


Управление количеством интервалов (thresholds)

Ключевой параметр биннинга — количество и расположение порогов (thresholds), определяющих границы интервалов.

Автоматическое количество бинов

const bin = d3.bin()
  .thresholds(10);

В этом случае диапазон делится на 10 равных частей.


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

const bin = d3.bin()
  .thresholds([10, 20, 30, 40, 50]);

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


Функции порогов

D3 предоставляет встроенные стратегии вычисления порогов:

  • d3.thresholdFreedmanDiaconis
  • d3.thresholdScott
  • d3.thresholdSturges

Пример:

const bin = d3.bin()
  .thresholds(d3.thresholdFreedmanDiaconis);

Эти методы адаптируют разбиение под статистические свойства данных, такие как дисперсия и размер выборки.


Применение генератора к данным

После настройки генератора он вызывается как функция:

const data = [1, 2, 2, 3, 5, 7, 8, 9, 9, 10];

const bins = bin(data);

Результат представляет собой массив бинов:

[
  [1, 2, 2],
  [3],
  [],
  [5],
  [],
  [7],
  [8],
  [9, 9],
  [10]
]

Каждый элемент массива дополнительно содержит:

bins[0].x0  // левая граница
bins[0].x1  // правая граница

Формирование гистограммы из бинов

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

svg.selectAll("rect")
  .data(bins)
  .enter()
  .append("rect")
  .attr("x", d => xScale(d.x0))
  .attr("y", d => yScale(d.length))
  .attr("width", d => xScale(d.x1) - xScale(d.x0))
  .attr("height", d => height - yScale(d.length));

В этом контексте:

  • d.length определяет частоту попадания значений в бин;
  • x0 и x1 задают геометрию столбца;
  • масштабирование выполняется через шкалы D3.

Влияние масштаба данных на биннинг

Корректность распределения зависит от предварительного понимания данных:

  • узкий диапазон приводит к высокой детализации;
  • широкий диапазон увеличивает обобщение;
  • выбросы могут смещать автоматические пороги.

При необходимости данные нормализуются перед биннингом или ограничиваются через domain.


Непрерывные и дискретные данные

d3.bin наиболее эффективен при работе с:

  • непрерывными значениями (время, температура, цена);
  • большими наборами чисел;
  • данными, требующими выявления плотности распределения.

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


Пользовательские стратегии разбиения

В сложных сценариях пороги могут формироваться вручную через внешние алгоритмы:

const thresholds = Array.from({length: 20}, (_, i) => i * 5);

const bin = d3.bin()
  .thresholds(thresholds);

Такой подход позволяет синхронизировать гистограммы с бизнес-логикой или внешними метриками.


Поведение пустых интервалов

Если в диапазоне отсутствуют значения, соответствующий бин остаётся пустым массивом. Такие интервалы сохраняются в результате, что позволяет корректно визуализировать нулевые частоты.


Внутренняя структура результата

Каждый бин представляет собой массив с дополнительными свойствами:

{
  0: value1,
  1: value2,
  length: n,
  x0: a,
  x1: b
}

Таким образом, структура сочетает массив значений и метаданные интервала.


Использование с масштабами времени

При работе с временными рядами применяются временные шкалы:

const bin = d3.bin()
  .value(d => d.date)
  .domain([new Date(2020, 0, 1), new Date(2021, 0, 1)])
  .thresholds(d3.timeMonth);

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


Связь с визуализацией плотности

Биннинг является основой для:

  • гистограмм распределения;
  • оценки плотности вероятности;
  • предварительной агрегации перед построением более сложных визуализаций.

Корректная настройка d3.bin определяет точность и читаемость результирующих графиков.