Степенные шкалы в D3.js используются для преобразования данных с нелинейным характером распределения, где изменение значения происходит по степенному закону. Такие шкалы особенно полезны при визуализации величин, различающихся на несколько порядков, но не требующих логарифмического сжатия.
Библиотека D3 предоставляет два основных инструмента для работы со степенными преобразованиями:
Степенная шкала реализует преобразование вида:
genui{“math_block_widget_always_prefetch_v2”:{“content”:“y = x^k”}}
где:
При:
Особый случай:
y = x^{0.5} =
const scale = d3.scalePow()
.exponent(1.5)
.domain([0, 100])
.range([0, 500]);
domain([min, max]) Определяет входной диапазон данных. Значения за пределами домена могут быть интерполированы или обрезаны при включённом clamp.
range([min, max]) Определяет выходной диапазон визуализации (например, пиксели на экране).
exponent(k) Задаёт степень преобразования:
d3.scalePow().exponent(0.5)
d3.scalePow().exponent(2)
d3.scalePow().exponent(3)
При использовании scalePow() преобразование происходит
по следующей логике:
Нормализация входного значения:
Применение степени:
Линейное масштабирование в range
const scale = d3.scalePow()
.exponent(0.5)
.domain([0, 100])
.range([0, 300]);
console.log(scale(25)); // ближе к началу диапазона
console.log(scale(100)); // 300
При exponent < 1 малые значения визуально растягиваются, а большие сжимаются.
const scale = d3.scalePow()
.exponent(2)
.domain([0, 10])
.range([0, 500]);
console.log(scale(2)); // небольшое значение
console.log(scale(8)); // резко увеличенное значение
При exponent > 1 шкала становится чувствительной к большим значениям.
d3.scaleSqrt() является упрощённой формой степенной
шкалы с фиксированным показателем:
d3.scaleSqrt() === d3.scalePow().exponent(0.5)
const scale = d3.scaleSqrt()
.domain([0, 100])
.range([0, 200]);
Отсутствует необходимость задавать exponent:
d3.scaleSqrt()
вместо:
d3.scalePow().exponent(0.5)
Корневая шкала часто используется для:
Причина — площадь объекта растёт квадратично, и прямое линейное масштабирование искажает восприятие.
Если значение отображается как радиус круга:
genui{“math_block_widget_always_prefetch_v2”:{“content”:“A = r^2”}}
то при линейной шкале увеличение значения приводит к квадратичному росту площади. Использование квадратного корня компенсирует этот эффект:
r =
Таким образом визуальная площадь становится пропорциональной исходному значению.
scalePow() — полностью настраиваемая степеньscaleSqrt() — фиксированный частный случайd3.scaleSqrt()
выражает намерение напрямую, тогда как:
d3.scalePow().exponent(0.5)
требует интерпретации.
scalePow() позволяет реализовать:
scaleSqrt() ограничен одним сценарием.
Обе шкалы поддерживают обратное преобразование:
const scale = d3.scaleSqrt()
.domain([0, 100])
.range([0, 400]);
scale.invert(200); // возвращает исходное значение
Инверсия важна при:
scale.clamp(true);
При включённом clamp значения за пределами domain ограничиваются границами диапазона.
Это предотвращает:
const radiusScale = d3.scaleSqrt()
.domain([1, 1000])
.range([2, 30]);
Применение:
const sizeScale = d3.scalePow()
.exponent(0.6)
.domain([0, 100000])
.range([0, 50]);
Позволяет сгладить резкие различия между регионами.
const r = d3.scaleSqrt()
.domain([minValue, maxValue])
.range([3, 20]);
Без корневой шкалы большие значения доминируют визуально, нарушая баланс восприятия.
Степенные шкалы поддерживают интерполяцию через встроенный механизм D3:
d3.interpolateRgb (при
использовании range с цветами)Степенные шкалы совместимы с осями D3:
const axis = d3.axisBottom(scale)
.ticks(5);
Однако распределение тиков может быть неравномерным из-за нелинейности функции.
genui{“math_block_widget_always_prefetch_v2”:{“content”:“y = x”}}
genui{“math_block_widget_always_prefetch_v2”:{“content”:“y = (x)”}}
genui{“math_block_widget_always_prefetch_v2”:{“content”:“y = x^k”}}
При значениях domain, включающих 0:
Степенные шкалы:
Степенные шкалы часто комбинируются с:
d3.scaleColor (цветовые интерпретации)d3.scaleTime (временные ряды)d3.scaleLinear (координаты)Пример комбинированного подхода:
const xScale = d3.scaleTime().domain([...]).range([...]);
const rScale = d3.scaleSqrt().domain([...]).range([...]);
const cScale = d3.scaleSequential(d3.interpolateViridis).domain([...]);
При использовании переходов D3:
selection.transition()
.attr("r", d => scale(d.value));
степенная шкала обеспечивает: