Преобразование и манипуляции с цветом

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

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


Цветовые модели: RGB, HSL и LAB

RGB как базовое представление

RGB (Red, Green, Blue) является наиболее прямолинейной моделью. В ней цвет задаётся тремя каналами интенсивности:

  • R — красный компонент
  • G — зелёный компонент
  • B — синий компонент

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

Однако линейная интерполяция RGB не всегда соответствует восприятию человека: переходы могут выглядеть неравномерными.


HSL: интуитивная модель оттенков

HSL (Hue, Saturation, Lightness) вводит более «человекоцентричное» описание цвета:

  • Hue — оттенок (угол на цветовом круге)
  • Saturation — насыщенность
  • Lightness — светлота

HSL особенно удобен для:

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

В D3.js HSL активно используется через модуль d3-color.


LAB: перцептуально равномерное пространство

LAB (CIELAB) моделирует восприятие цвета человеком. В отличие от RGB, расстояния в LAB ближе к визуальной «равномерности».

  • L — светлота
  • a — зелёно-красная ось
  • b — сине-жёлтая ось

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


Модуль d3-color

Модуль d3-color предоставляет базовые типы и преобразования цветовых пространств.

Основные возможности:

  • парсинг строковых представлений цветов (#rrggbb, rgb(), hsl())
  • преобразование между RGB, HSL, LAB
  • модификация цветовых компонентов

Пример логики работы с цветом:

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

Интерполяция — ключевой механизм анимации и переходов.

Модуль d3-interpolate определяет функцию перехода между двумя значениями:

[ t value(t)]

Для цветов это означает плавный переход между двумя оттенками.

RGB-интерполяция

Простейший вариант:

import { interpolateRgb } from "d3-interpolate";

const i = interpolateRgb("red", "blue");
console.log(i(0.5));

Проблема RGB-интерполяции — неравномерность восприятия.


HSL-интерполяция

Более интуитивный переход по оттенку:

import { interpolateHsl } from "d3-interpolate";

const i = interpolateHsl("red", "blue");

Здесь сохраняется восприятие насыщенности и светлоты, а изменяется оттенок.


LAB-интерполяция

Перцептуально корректный вариант:

import { interpolateLab } from "d3-interpolate";

const i = interpolateLab("red", "blue");

LAB используется для аналитических визуализаций, где важна точность восприятия градиентов.


Цветовые шкалы: d3-scale

Механизм шкал связывает данные с цветом.

Линейные шкалы

import { scaleLinear } from "d3-scale";

const colorScale = scaleLinear()
  .domain([0, 100])
  .range(["white", "steelblue"]);

Значения автоматически интерполируются через выбранный цветовой интерполятор.


Sequential scales

Используются для непрерывных данных:

import { scaleSequential } from "d3-scale";
import { interpolateViridis } from "d3-scale-chromatic";

const scale = scaleSequential(interpolateViridis)
  .domain([0, 1]);

Sequential шкалы часто применяются в тепловых картах и плотностных визуализациях.


Diverging scales

Используются для данных с центральной точкой:

import { scaleDiverging } from "d3-scale";
import { interpolateRdBu } from "d3-scale-chromatic";

const scale = scaleDiverging(interpolateRdBu)
  .domain([-1, 0, 1]);

Такие шкалы полезны для отображения отклонений от нормы.


Ordinal scales

Категориальные цвета:

import { scaleOrdinal } from "d3-scale";

const scale = scaleOrdinal()
  .domain(["A", "B", "C"])
  .range(["red", "green", "blue"]);

Цветовые палитры d3-scale-chromatic

Модуль d3-scale-chromatic предоставляет готовые интерполяции:

  • interpolateViridis
  • interpolateInferno
  • interpolateMagma
  • interpolatePlasma
  • interpolateTurbo

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

Пример:

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, выделения элементов и построения иерархий.


Прозрачность и alpha-канал

const semi = c.opacity(0.5);

Прозрачность используется для:

  • наложения слоёв
  • отображения плотности
  • визуализации неопределённости

Смешивание цветов

Интерполяция фактически является формой смешивания:

import { interpolateRgb } from "d3-interpolate";

const mix = interpolateRgb("red", "green")(0.25);

Для сложных случаев применяются LAB или HSL.


Перцептуальная согласованность

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

RGB-интерполяция может создавать визуальные «скачки», тогда как LAB обеспечивает более равномерные переходы.

Сравнение подходов:

  • RGB — быстро, но визуально неравномерно
  • HSL — интуитивно, но искажения возможны в насыщенности
  • 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);
  });

Градиенты через SVG

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 для аналитических шкал приводит к неравномерным визуальным переходам.


Избыточная насыщенность

Высокая насыщенность всех элементов снижает читаемость визуализации.


Игнорирование контекста данных

Категориальные данные требуют дискретных палитр, а непрерывные — градиентов.


Несогласованность палитр

Смешивание различных цветовых схем в одном графике приводит к потере смысловой структуры.