Диаграмма Аллювия

Диаграмма аллювия представляет собой специализированный вариант потоковой визуализации, в котором данные отображаются как совокупность «ручьёв» (flows), изменяющих свою структуру при переходе между дискретными измерениями. Каждая линия отражает группу объектов, сохраняющих идентичность через несколько категорий, а ширина потока кодирует величину или частоту.

В контексте Vega и Vega-Lite такие диаграммы чаще всего реализуются через Sankey-структуры или через комбинацию трансформаций stack, window и геометрии связей.


Структурная модель аллювия

Аллювиальная диаграмма опирается на три базовых элемента:

  • Ось категорий (dimensions) — уровни, через которые проходят данные (например: год → регион → тип продукта).
  • Потоки (flows) — связи между категориями, формирующие непрерывные линии.
  • Вес (value) — количественная характеристика потока.

Типовая структура данных:

[
  { "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: Sankey как основа аллювия

Vega-Lite не предоставляет полноценного «alluvial mark» в классическом смысле, но поддерживает Sankey-подобную визуализацию через связи узлов и рёбер.

Основная идея:

  • узлы = категории на каждом уровне
  • рёбра = переходы между уровнями
  • ширина = сумма значений

Базовая структура Sankey в Vega-Lite

{
  "$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 (низкий уровень)

Vega предоставляет более гибкий механизм, включая layout-алгоритмы и контроль геометрии потоков. Аллювий часто строится на основе sankey transform.

Пример базового Sankey в Vega

{
  "$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 контроль над трансформацией позволяет более точно моделировать многоуровневые аллювиальные структуры.


Аллювий через многослойные категории (parallel sets)

Классический alluvial chart чаще всего строится не как граф, а как последовательность категориальных осей.

Подход parallel sets:

  1. Каждая ось — отдельная категория (stage)
  2. Данные агрегируются по комбинациям
  3. Используется stack для вертикального распределения
  4. Используется 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}
]

Часто это достигается через:

  • aggregate
  • joinaggregate
  • window
  • предварительную обработку вне Vega (ETL)

Использование transform: window для накопления потоков

Vega-Lite позволяет формировать накопленные значения:

{
  "transform": [
    {
      "window": [
        {"op": "sum", "field": "value", "as": "cum_value"}
      ],
      "groupby": ["stage"],
      "sort": [{"field": "group"}]
    }
  ]
}

Это используется для расчёта вертикального позиционирования потоков.


Геометрия потоков

Аллювий требует непрерывных кривых между узлами.

В Vega это реализуется через:

  • mark: path
  • интерполяцию линий
  • контроль контрольных точек Bézier-кривых

Типовая логика:

  • X = стадия (stage index)
  • Y = позиция внутри категории
  • толщина = value

Связи через linkpath

В 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"}
}

В более сложных моделях применяется:

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

Разделение узлов и потоков

Архитектурно аллювиальная диаграмма всегда разделяется на:

Узлы (nodes)

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

Типичная схема Vega для аллювия (обобщённая)

{
  "data": [
    {"name": "nodes"},
    {"name": "links"}
  ],
  "scales": [],
  "axes": [],
  "marks": [
    {
      "type": "rect",
      "from": {"data": "nodes"}
    },
    {
      "type": "path",
      "from": {"data": "links"}
    }
  ]
}

Обработка многомерных переходов

Аллювиальные диаграммы усложняются при более чем двух стадиях:

  • stage 1 → stage 2 → stage 3 → stage N

В таких случаях применяются:

  • каскадные Sankey-графы
  • последовательные link-таблицы
  • нормализация по уровням

Ограничения Vega-Lite

При построении сложных аллювиальных диаграмм в Vega-Lite проявляются ограничения:

  • слабый контроль над layout-алгоритмами
  • ограниченная кастомизация кривых
  • необходимость предобработки данных
  • невозможность сложных пересечений потоков без перехода в Vega

Практическая архитектура построения

Типичный pipeline:

  1. Исходные события
  2. Агрегация переходов
  3. Построение матрицы source–target
  4. Расчёт весов
  5. Генерация Vega/Vega-Lite spec
  6. Layout (Sankey или custom transform)
  7. Рендер path-геометрии

Аллювий как частный случай потоковых графов

С точки зрения Vega:

  • аллювий = расширенный Sankey
  • Sankey = частный случай weighted directed graph
  • parallel sets = категориальная проекция многомерного графа

Различие определяется не только визуально, но и структурой данных и алгоритмом layout.


Использование нескольких уровней агрегации

Для повышения читаемости применяется:

  • сглаживание потоков
  • группировка редких категорий в «Other»
  • иерархическая агрегация
{
  "aggregate": [
    {"op": "sum", "field": "value", "as": "total"}
  ],
  "groupby": ["source", "target"]
}

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

Каждый поток можно представить как функцию:

  • ширина = f(value)
  • положение = g(stage, category rank)
  • кривизна = h(layout constraints)

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


Согласование визуальной стабильности

При динамических данных важно сохранять:

  • постоянство порядка категорий
  • устойчивость потоков между обновлениями
  • минимизацию «перескоков» линий

Vega решает это через фиксированные сортировки и стабильные ключи группировки.


Комбинация с интерактивностью

Хотя аллювий часто статичен, Vega поддерживает:

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

Интерактивность добавляется через signals и event streams.


Сигнальная модель Vega

"signals": [
  {
    "name": "hover",
    "on": [
      {"events": "path:mouseover", "update": "datum"}
    ]
  }
]

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


Связь с реальными кейсами

Аллювиальные диаграммы в Vega/Vega-Lite применяются для:

  • миграции пользователей между сервисами
  • финансовых потоков между категориями
  • переходов состояний (state transitions)
  • анализов воронок
  • цепочек поставок

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