Цвет в визуализации данных выступает не декоративным элементом, а полноценным каналом передачи информации. В экосистеме D3.js работа с цветом строится на сочетании нескольких уровней абстракции: низкоуровневые представления цветовых моделей, интерполяция значений, шкалы отображения данных и готовые палитры.
Ключевая идея заключается в том, что цвет рассматривается как численно интерполируемая сущность. Это позволяет плавно преобразовывать значения, строить градиенты, динамически изменять визуальные свойства графиков и обеспечивать согласованность между различными типами визуализаций.
RGB (Red, Green, Blue) является наиболее прямолинейной моделью. В ней цвет задаётся тремя каналами интенсивности:
В контексте D3 RGB часто используется как базовый формат, поскольку он напрямую поддерживается браузерами.
Однако линейная интерполяция RGB не всегда соответствует восприятию человека: переходы могут выглядеть неравномерными.
HSL (Hue, Saturation, Lightness) вводит более «человекоцентричное» описание цвета:
HSL особенно удобен для:
В D3.js HSL активно используется через модуль
d3-color.
LAB (CIELAB) моделирует восприятие цвета человеком. В отличие от RGB, расстояния в LAB ближе к визуальной «равномерности».
LAB используется там, где важно избежать искажений при интерполяции, особенно в сложных градиентах и аналитических графиках.
Модуль d3-color предоставляет базовые типы и
преобразования цветовых пространств.
Основные возможности:
#rrggbb,
rgb(), hsl())Пример логики работы с цветом:
import { rgb, hsl, lab } from "d3-color";
const c1 = rgb(120, 200, 255);
const c2 = hsl("steelblue");
const converted = lab(c1);
Каждый объект цвета является изменяемым и поддерживает методы трансформации:
brighter()darker()opacity()Интерполяция — ключевой механизм анимации и переходов.
Модуль d3-interpolate определяет функцию перехода между
двумя значениями:
[ t value(t)]
Для цветов это означает плавный переход между двумя оттенками.
Простейший вариант:
import { interpolateRgb } from "d3-interpolate";
const i = interpolateRgb("red", "blue");
console.log(i(0.5));
Проблема RGB-интерполяции — неравномерность восприятия.
Более интуитивный переход по оттенку:
import { interpolateHsl } from "d3-interpolate";
const i = interpolateHsl("red", "blue");
Здесь сохраняется восприятие насыщенности и светлоты, а изменяется оттенок.
Перцептуально корректный вариант:
import { interpolateLab } from "d3-interpolate";
const i = interpolateLab("red", "blue");
LAB используется для аналитических визуализаций, где важна точность восприятия градиентов.
Механизм шкал связывает данные с цветом.
import { scaleLinear } from "d3-scale";
const colorScale = scaleLinear()
.domain([0, 100])
.range(["white", "steelblue"]);
Значения автоматически интерполируются через выбранный цветовой интерполятор.
Используются для непрерывных данных:
import { scaleSequential } from "d3-scale";
import { interpolateViridis } from "d3-scale-chromatic";
const scale = scaleSequential(interpolateViridis)
.domain([0, 1]);
Sequential шкалы часто применяются в тепловых картах и плотностных визуализациях.
Используются для данных с центральной точкой:
import { scaleDiverging } from "d3-scale";
import { interpolateRdBu } from "d3-scale-chromatic";
const scale = scaleDiverging(interpolateRdBu)
.domain([-1, 0, 1]);
Такие шкалы полезны для отображения отклонений от нормы.
Категориальные цвета:
import { scaleOrdinal } from "d3-scale";
const scale = scaleOrdinal()
.domain(["A", "B", "C"])
.range(["red", "green", "blue"]);
Модуль d3-scale-chromatic предоставляет готовые
интерполяции:
interpolateViridisinterpolateInfernointerpolateMagmainterpolatePlasmainterpolateTurboЭти палитры обладают свойством перцептуальной равномерности и подходят для научной визуализации.
Пример:
import { scaleSequential } from "d3-scale";
import { interpolateInferno } from "d3-scale-chromatic";
const color = scaleSequential(interpolateInferno);
Через методы d3-color:
import { rgb } from "d3-color";
const c = rgb("steelblue");
const brighter = c.brighter(1.5);
const darker = c.darker(1.5);
Эти операции полезны для состояния hover, выделения элементов и построения иерархий.
const semi = c.opacity(0.5);
Прозрачность используется для:
Интерполяция фактически является формой смешивания:
import { interpolateRgb } from "d3-interpolate";
const mix = interpolateRgb("red", "green")(0.25);
Для сложных случаев применяются LAB или HSL.
Одной из ключевых проблем цветовой визуализации является несоответствие между численным расстоянием и восприятием.
RGB-интерполяция может создавать визуальные «скачки», тогда как LAB обеспечивает более равномерные переходы.
Сравнение подходов:
Цвет в D3 тесно связан с системой переходов:
selection.transition()
.duration(1000)
.style("fill", "orange");
Внутри transition D3 автоматически использует интерполяторы, если начальное и конечное значения являются цветами.
Это позволяет:
const scale = scaleSequential()
.domain([min, max])
.interpolator(interpolateViridis);
selection
.style("fill", d => scale(d.value));
const base = rgb("steelblue");
const highlight = base.brighter(2);
selection
.on("mouseover", function() {
d3.select(this).style("fill", highlight);
});
const gradient = svg.append("linearGradient")
.attr("id", "grad");
gradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", "red");
gradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", "blue");
Использование RGB для аналитических шкал приводит к неравномерным визуальным переходам.
Высокая насыщенность всех элементов снижает читаемость визуализации.
Категориальные данные требуют дискретных палитр, а непрерывные — градиентов.
Смешивание различных цветовых схем в одном графике приводит к потере смысловой структуры.