Chord-диаграмма: d3.chord() и d3.ribbon()

Chord-диаграмма предназначена для визуализации взаимосвязей между группами данных в виде круговой структуры, где элементы представлены дугами окружности, а связи — изогнутыми лентами между ними. Основой такой диаграммы является матрица связей, где значения определяют силу или вес отношений между узлами.

Ключевые элементы chord-диаграммы:

  • Сектора (arcs) — группы данных по окружности
  • Chord (связи) — дугообразные ленты между секторами
  • Матрица связей — исходная структура данных
  • Компоновка (layout) — вычисление углов и позиций

Матрица как исходная структура данных

Chord-диаграмма в D3 строится исключительно на основе квадратной матрицы:

[
  [0, 10, 20],
  [10, 0, 5],
  [20, 5, 0]
]

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

Смысл матрицы:

  • строки — исходящие связи
  • столбцы — входящие связи
  • значения — вес взаимодействия

d3.chord(): генерация структуры диаграммы

Функция d3.chord() преобразует матрицу в набор геометрических данных для построения диаграммы.

Основная роль d3.chord

Функция выполняет:

  • вычисление углов для каждой группы
  • распределение секторов по окружности
  • расчёт связей между элементами
  • сортировку и оптимизацию размещения дуг

Конфигурация chord layout

const chord = d3.chord()
  .padAngle(0.05)
  .sortSubgroups(d3.descending)
  .sortChords(d3.descending);

padAngle

Определяет расстояние между секторами:

  • значение 0 — отсутствует зазор
  • увеличенное значение — визуальное разделение групп

sortSubgroups

Управляет порядком внутренних связей:

  • d3.descending — сортировка по убыванию веса
  • d3.ascending — по возрастанию

sortChords

Определяет порядок отображения связей, влияя на перекрытие линий.


Структура результата d3.chord()

После применения chord(matrix) возвращается объект с двумя основными частями:

  • groups — массив секторов
  • chords — массив связей

groups

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

  • startAngle
  • endAngle
  • value
  • index

Пример структуры:

{
  startAngle: 0.2,
  endAngle: 1.1,
  value: 30,
  index: 0
}

chords

Каждая связь содержит:

  • source
  • target
{
  source: { startAngle, endAngle, index, value },
  target: { startAngle, endAngle, index, value }
}

Построение дуг: d3.arc()

Сектора окружности создаются через arc-генератор:

const arc = d3.arc()
  .innerRadius(200)
  .outerRadius(210);

Использование:

svg.append("g")
  .selectAll("path")
  .data(chords.groups)
  .join("path")
  .attr("d", arc);

Параметры радиусов

  • innerRadius — внутренний радиус кольца
  • outerRadius — внешний радиус

Разница между ними формирует толщину сектора.


Связи между группами: d3.ribbon()

Функция d3.ribbon() отвечает за визуализацию связей между секторами.

const ribbon = d3.ribbon()
  .radius(200);

Структура ribbon-элемента

Каждый ribbon использует:

  • source (углы начала и конца)
  • target (углы начала и конца)

Отрисовка связей

svg.append("g")
  .selectAll("path")
  .data(chords)
  .join("path")
  .attr("d", ribbon);

Различие между d3.arc и d3.ribbon

Элемент Назначение Геометрия
arc сектора дуги окружности
ribbon связи кривые между секторами

Цветовое кодирование

Цвета обычно назначаются на основе индекса группы:

const color = d3.scaleOrdinal(d3.schemeCategory10);

.attr("fill", d => color(d.index))

Для связей часто применяется цвет источника:

.attr("fill", d => color(d.source.index))

Преобразование координат

Chord-диаграмма использует радианные углы:

  • 0 — начало окружности
  • 2π — полный оборот

Перевод углов в экранные координаты происходит внутри arc и ribbon генераторов.


Работа с направленностью связей

Матрица может быть:

  • симметричной — неориентированный граф
  • асимметричной — направленные связи

В случае асимметрии:

  • source ≠ target
  • ribbon отображает направление через толщину или цвет

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

Сортировка групп

d3.chord().sortGroups(d3.descending)

Позволяет упорядочить сектора по суммарному весу.

Минимизация пересечений

Используются:

  • sortSubgroups
  • sortChords

Это снижает визуальный шум при большом количестве связей.


Масштабирование диаграммы

Для корректного отображения используется центрирование:

svg.attr("transform", "translate(width/2,height/2)");

Все элементы строятся относительно центра окружности.


Пример полной структуры построения

const matrix = [
  [0, 10, 30],
  [10, 0, 5],
  [30, 5, 0]
];

const chord = d3.chord()
  .padAngle(0.05)
  .sortSubgroups(d3.descending);

const chords = chord(matrix);

const arc = d3.arc()
  .innerRadius(200)
  .outerRadius(210);

const ribbon = d3.ribbon()
  .radius(200);

const svg = d3.select("svg")
  .attr("viewBox", [-300, -300, 600, 600]);

svg.append("g")
  .selectAll("path")
  .data(chords.groups)
  .join("path")
  .attr("d", arc);

svg.append("g")
  .selectAll("path")
  .data(chords)
  .join("path")
  .attr("d", ribbon);

Геометрическая интерпретация связей

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

  • начальной точкой source
  • конечной точкой target

Толщина ленты зависит от значения матрицы.


Масштабирование веса связей

При больших различиях значений используется нормализация:

  • линейная
  • логарифмическая

Это влияет на ширину ribbon, так как она пропорциональна весу связи.


Управление плотностью диаграммы

Параметр padAngle влияет на:

  • читаемость при большом числе групп
  • визуальное разделение сегментов
  • восприятие кластеров

Увеличение значения улучшает различимость, но снижает плотность информации.


Взаимосвязь layout и rendering

Процесс построения состоит из двух этапов:

  1. chord layout — вычисление углов и связей
  2. rendering — отрисовка arc и ribbon

Разделение этих этапов позволяет:

  • изменять визуализацию без пересчёта данных
  • применять разные стили отображения
  • переиспользовать layout для разных графиков