Распространенное заблуждение о D3 среди тех, кто еще не использовал его, заключается в том, что он предоставляет набор инструментов графиков и диаграмм, которые можно использовать для визуализации своих данных. То есть вы подключаете вход, выбираете «круговую диаграмму» и вуаля!, у вас есть визуализация. На самом деле, это более точно описывает множество библиотек построения диаграмм, построенных поверх D3, в то время как инструменты, которые предоставляет D3, находятся на более глубоком уровне.

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

Что такое шкала?

Шкалы в D3 — это на самом базовом уровне функции, которые принимают входное значение и возвращают выходное значение. Самый простой тип шкалы — это линейная шкала, которую мы можем определить следующим образом:

const scale = d3.scaleLinear()

Это дает нам функцию scale, которую мы можем передать в значениях:

scale(75) // returns 75

Но подождите… это только что вернуло нам наш вклад. Это связано с тем, что шкала дает нам тип отношения (в данном случае линейного), но для того, чтобы на самом деле его использовать, нам нужно определить границы этого отношения. Связь между входом и выходом определяется пользователем как домен и диапазон.

Домены и диапазоны

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

[5,24,31,85,97, 101, 138, 145]

мы могли бы настроить наш домен так, чтобы он простирался от самых низких до самых высоких значений в этом наборе, выраженном здесь как [5, 145]. Если бы мы выбирали ось диаграммы, возможно, имело бы смысл округлить эти значения до [0, 150].

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

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

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

Теперь, если мы попытаемся снова вызвать scale(75), вместо того, чтобы вернуть наше входное значение, мы получим 300. Точно так же, как 75 — это середина нашего домена (0-150), 300 — это середина нашего диапазона (100-500). Довольно круто, правда?

Непрерывные весы

В D3 существует множество различных масштабов, и линейные масштабы являются примером особого типа, известного как непрерывные масштабы. Как мы рассмотрели выше, непрерывная шкала может брать любую точку из входной области и возвращать соответствующую точку в выходном диапазоне.

Другими типами непрерывных шкал в D3 являются шкала мощности, логарифмическая шкала, шкала идентичности и шкала времени. Все они аналогичны линейным шкалам, но основное отличие заключается в преобразовании, которое применяется к входному значению до того, как будет вычислено выходное значение. В то время как линейные шкалы используют линейную функцию (y = m * x + b), шкалы мощности используют экспоненциальную функцию (y = m * x^k + b), логарифмические шкалы используют логарифмическую функцию и т. д.

Чтобы глубже понять, как именно работают непрерывные шкалы, давайте взглянем на код, из которого состоит D3. Если мы покопаемся, чтобы увидеть, где именно определена наша функция scaleLinear(), мы обнаружим следующее:

Если мы посмотрим на scalePow(), мы увидим нечто подобное:

Так что же именно здесь происходит? Функция linearish просто дает нам ticks, nice и некоторые другие классные функции, которые помогают нам форматировать наши весы. Основная часть работы происходит в continuous, который называется в определении каждой из непрерывных шкал D3.

continuous принимает два параметра, deinterpolate и reinterpolate, и это функции, определяющие поведение наших весов. Тело этих функций будет различаться в зависимости от того, какую непрерывную шкалу мы рассматриваем (линейную, степенную и т. д.), но в целом они ведут себя одинаково.

Комментарии Майка Бостока к коду D3 дают нам краткое объяснение того, как работают эти функции.

// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].

Другими словами, каждая функция принимает входные значения, которые мы указываем для нашего домена, и возвращает другую функцию, которая сама принимает значение. Для deinterpolate значение, которое он принимает, x, является любым значением в пределах [a, b] нашего домена. Он берет это значение x и преобразует его, возвращая значение t в диапазоне от 0 до 1. Функция reinterpolate — это просто обратная функция, которая дает нам функцию, которая принимает t в диапазоне от 0 до 1 и возвращает соответствующее значение x в пределах нашего домена.

Здесь происходит процесс, известный как нормализация, который представляет собой сопоставление значения с другим значением от 0 до 1 на основе возможных минимального и максимального значений. В приведенном выше примере линейной шкалы, где вызов scale(75) возвращает нам 300, функция, возвращаемая deinterpolate, принимает 75 и возвращает 0,5, или 50%, которые затем применяются к выходному диапазону, чтобы дать нам наш результат.

В конечном счете, это простая концепция, которая в конечном итоге становится сверхмощной. Непрерывные масштабы D3 абстрагируются от математики, лежащей в основе нормализации, и дают нам быстрый, многоразовый способ сопоставления значения в наборе входных данных с соответствующим значением в наборе выходных данных.

В заключении …

В D3 есть все виды различных гамм. Шкалы квантования, например, делят выходной диапазон на дискретные сегменты. Порядковые шкалы вообще не нуждаются в числовом домене и могут сопоставлять набор именованных категорий с набором цветов или с позициями на диаграмме. Ознакомьтесь с приведенными ниже ресурсами, чтобы узнать больше о масштабах и D3 в целом. Как только вы поймете, что может сделать эта мощная библиотека, возможности безграничны. Удачного кодирования!

Источники / Дополнительная литература