Диаграмма аллювия представляет собой специализированный вариант потоковой визуализации, в котором данные отображаются как совокупность «ручьёв» (flows), изменяющих свою структуру при переходе между дискретными измерениями. Каждая линия отражает группу объектов, сохраняющих идентичность через несколько категорий, а ширина потока кодирует величину или частоту.
В контексте Vega и Vega-Lite такие диаграммы чаще всего реализуются
через Sankey-структуры или через комбинацию трансформаций
stack, window и геометрии связей.
Аллювиальная диаграмма опирается на три базовых элемента:
Типовая структура данных:
[
{ "stage": "A", "group": "X", "value": 10 },
{ "stage": "A", "group": "Y", "value": 20 },
{ "stage": "B", "group": "X", "value": 15 },
{ "stage": "B", "group": "Y", "value": 15 }
]
Для аллювия важно, чтобы данные были либо уже агрегированы по переходам, либо поддавались агрегации внутри спецификации.
Vega-Lite не предоставляет полноценного «alluvial mark» в классическом смысле, но поддерживает Sankey-подобную визуализацию через связи узлов и рёбер.
Основная идея:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"source": "A", "target": "B", "value": 10},
{"source": "A", "target": "C", "value": 20},
{"source": "B", "target": "D", "value": 15},
{"source": "C", "target": "D", "value": 15}
]
},
"mark": "sankey",
"encoding": {
"source": {"field": "source"},
"target": {"field": "target"},
"size": {"field": "value"}
}
}
В реальных версиях Vega-Lite синтаксис может отличаться в зависимости от сборки, но логика остаётся устойчивой: граф «источник–приёмник» с взвешенными связями.
Vega предоставляет более гибкий механизм, включая layout-алгоритмы и
контроль геометрии потоков. Аллювий часто строится на основе
sankey transform.
{
"$schema": "https://vega.github.io/schema/vega/v5.json",
"data": [
{
"name": "links",
"values": [
{"source": "A", "target": "B", "value": 10},
{"source": "A", "target": "C", "value": 20},
{"source": "B", "target": "D", "value": 15},
{"source": "C", "target": "D", "value": 15}
]
}
],
"marks": [
{
"type": "path",
"from": {"data": "links"},
"encode": {
"update": {
"strokeWidth": {"scale": "size", "field": "value"},
"stroke": {"value": "#4c78a8"}
}
},
"transform": [
{
"type": "sankey",
"nodes": "nodes",
"links": "links",
"source": "source",
"target": "target",
"value": "value"
}
]
}
]
}
В Vega контроль над трансформацией позволяет более точно моделировать многоуровневые аллювиальные структуры.
Классический alluvial chart чаще всего строится не как граф, а как последовательность категориальных осей.
stack для вертикального распределенияlinkpath или rule для
соединения сегментовКлючевой этап — преобразование «плоских» данных в переходную форму.
Исходные данные:
[
{"year": 2020, "region": "EU", "product": "A", "value": 30},
{"year": 2020, "region": "US", "product": "A", "value": 20},
{"year": 2021, "region": "EU", "product": "A", "value": 25}
]
Требуемая структура для потоков:
[
{"source": "2020-EU", "target": "2021-EU", "value": 25},
{"source": "2020-US", "target": "2021-US", "value": 20}
]
Часто это достигается через:
aggregatejoinaggregatewindowVega-Lite позволяет формировать накопленные значения:
{
"transform": [
{
"window": [
{"op": "sum", "field": "value", "as": "cum_value"}
],
"groupby": ["stage"],
"sort": [{"field": "group"}]
}
]
}
Это используется для расчёта вертикального позиционирования потоков.
Аллювий требует непрерывных кривых между узлами.
В Vega это реализуется через:
mark: pathТиповая логика:
В Vega используется специализированная геометрия для соединений:
{
"type": "linkpath",
"orient": "horizontal",
"shape": "diagonal"
}
Это создаёт плавные переходы между узлами, формируя визуально непрерывные потоки.
При построении аллювиальных диаграмм важны нормировки:
Пример масштабов:
"scales": [
{
"name": "y",
"type": "linear",
"domain": {"data": "flows", "field": "cum_value"},
"range": "height"
}
]
Цвет в аллювии выполняет две функции:
В Vega-Lite:
"encoding": {
"color": {"field": "group", "type": "nominal"}
}
В более сложных моделях применяется:
Архитектурно аллювиальная диаграмма всегда разделяется на:
{
"data": [
{"name": "nodes"},
{"name": "links"}
],
"scales": [],
"axes": [],
"marks": [
{
"type": "rect",
"from": {"data": "nodes"}
},
{
"type": "path",
"from": {"data": "links"}
}
]
}
Аллювиальные диаграммы усложняются при более чем двух стадиях:
В таких случаях применяются:
При построении сложных аллювиальных диаграмм в Vega-Lite проявляются ограничения:
Типичный pipeline:
С точки зрения Vega:
Различие определяется не только визуально, но и структурой данных и алгоритмом layout.
Для повышения читаемости применяется:
{
"aggregate": [
{"op": "sum", "field": "value", "as": "total"}
],
"groupby": ["source", "target"]
}
Каждый поток можно представить как функцию:
Это делает аллювий не просто диаграммой, а результатом оптимизационной задачи размещения.
При динамических данных важно сохранять:
Vega решает это через фиксированные сортировки и стабильные ключи группировки.
Хотя аллювий часто статичен, Vega поддерживает:
Интерактивность добавляется через signals и event streams.
"signals": [
{
"name": "hover",
"on": [
{"events": "path:mouseover", "update": "datum"}
]
}
]
Это позволяет динамически изменять прозрачность потоков и выделять связи.
Аллювиальные диаграммы в Vega/Vega-Lite применяются для:
Каждый кейс требует собственной схемы агрегации, но визуальный каркас остаётся одинаковым: потоковая структура между дискретными стадиями.