Диаграмма Сэнки в Vega строится на представлении потоков как
направленных связей между узлами, где ширина ребра пропорциональна
величине потока. В экосистеме Vega это реализуется через набор
преобразований данных и специализированный layout-алгоритм, чаще всего
предоставляемый расширением vega-sankey, которое добавляет
вычисление координат узлов и изгибов связей.
Базовая модель включает два типа сущностей:
Типичная структура исходного набора данных:
{
"nodes": [
{ "name": "A" },
{ "name": "B" },
{ "name": "C" }
],
"links": [
{ "source": "A", "target": "B", "value": 10 },
{ "source": "A", "target": "C", "value": 5 },
{ "source": "B", "target": "C", "value": 3 }
]
}
В Vega эта структура может использоваться напрямую или
нормализоваться через трансформации lookup и
fold, если данные поступают в разрозненном виде.
Алгоритм размещения в Sankey-графах решает две ключевые задачи:
В Vega используется итеративная оптимизация:
Каждый узел получает координаты:
x — уровень (шаг по оси направления потока)y — позиция внутри уровняТолщина ребра вычисляется как функция value.
Vega не включает Sankey как базовый mark, поэтому применяется внешний трансформ:
{
"type": "sankey",
"nodeWidth": 15,
"nodePadding": 10,
"extent": [[1, 1], [500, 300]]
}
Этот трансформ:
В зависимости от версии Vega используется пакет
vega-transforms или отдельный модуль
vega-sankey.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"width": 600,
"height": 300,
"padding": 5,
"data": [
{
"name": "sankey",
"values": {
"nodes": [
{ "name": "Источник" },
{ "name": "Промежуточный" },
{ "name": "Сток" }
],
"links": [
{ "source": "Источник", "target": "Промежуточный", "value": 12 },
{ "source": "Промежуточный", "target": "Сток", "value": 7 },
{ "source": "Источник", "target": "Сток", "value": 5 }
]
},
"transform": [
{
"type": "sankey",
"nodeWidth": 20,
"nodePadding": 12,
"iterations": 32
}
]
}
],
"marks": [
{
"type": "path",
"from": { "data": "sankey" },
"encode": {
"enter": {
"path": { "field": "path" },
"stroke": { "value": "#888" },
"strokeOpacity": { "value": 0.4 }
},
"update": {
"strokeWidth": { "field": "value" }
}
}
},
{
"type": "rect",
"from": { "data": "sankey.nodes" },
"encode": {
"enter": {
"x": { "field": "x0" },
"x2": { "field": "x1" },
"y": { "field": "y0" },
"y2": { "field": "y1" },
"fill": { "value": "#4c78a8" }
}
}
}
]
}
В данной схеме:
sankey трансформирует входные данные в геометриюpath хранит кривые потоковrect визуализирует узлыСвязи в Sankey представляются кубическими кривыми Безье. Каждая связь определяется четырьмя точками:
Форма кривой формируется так, чтобы:
Толщина ребра:
[ w_i = k value_i]
где коэффициент масштабирования k зависит от общей
высоты слоя.
Распределение по уровням строится на основе направленного графа:
Каждому узлу присваивается глубина depth, которая затем
преобразуется в координату x.
Для корректного отображения применяется балансировка:
Это важно для сохранения визуальной пропорциональности.
Параметры layout-а определяют читаемость диаграммы:
nodePadding задаёт расстояние между узламиnodeWidth определяет толщину блокаiterations влияет на стабильность размещенияУвеличение числа итераций:
Vega-Lite не имеет нативного Sankey mark, поэтому используются подходы:
toVegavega-sankey через расширениеТипичный сценарий:
Цвета применяются для:
Пример:
"encode": {
"update": {
"stroke": { "scale": "color", "field": "source" }
}
}
Шкала цветов обычно дискретная (ordinal), что позволяет
различать категории без смешивания оттенков.
Sankey-диаграммы в Vega поддерживают интерактивные преобразования:
Добавление сигналов:
"signals": [
{
"name": "highlight",
"value": null,
"on": [
{ "events": "rect:mouseover", "update": "datum.name" },
{ "events": "rect:mouseout", "update": "null" }
]
}
]
Это позволяет изменять визуальное представление без пересборки графа.
При увеличении количества узлов и связей возникают ограничения:
Используются методы:
В некоторых случаях применяется двухуровневая Sankey-схема, где верхний уровень агрегирует категории, а нижний раскрывает детали.