Иерархические данные представляют собой один из наиболее естественных способов структурирования информации: каталоги файлов, организационные схемы, классификации, биологические таксономии. В визуализации такие структуры требуют специальных алгоритмов раскладки, поскольку стандартные координатные системы не отражают отношения «родитель–потомок».
В Vega и Vega-Lite для работы с иерархиями применяются два базовых подхода: представление через плоский список с последующей реконструкцией дерева (stratify), либо использование уже вложенной структуры данных. Дальнейшая визуализация строится через специализированные трансформации и layout-алгоритмы: treemap, pack, tree, cluster.
Для построения древовидных визуализаций используется два основных формата:
1. Плоская структура (edge list) Каждая запись содержит идентификатор и ссылку на родителя:
[
{"id": "A", "parent": null, "value": 10},
{"id": "B", "parent": "A", "value": 5},
{"id": "C", "parent": "A", "value": 8},
{"id": "D", "parent": "B", "value": 2}
]
2. Вложенная структура (tree object)
{
"name": "A",
"children": [
{
"name": "B",
"children": [
{"name": "D", "value": 2}
]
},
{
"name": "C",
"value": 8
}
]
}
Vega чаще использует первый формат с последующей трансформацией
stratify, тогда как Vega-Lite допускает вложенные данные в
ограниченных сценариях.
Трансформация stratify преобразует плоский список в
дерево:
{
"data": {
"values": [
{"id": "A", "parent": null, "value": 10},
{"id": "B", "parent": "A", "value": 5},
{"id": "C", "parent": "A", "value": 8},
{"id": "D", "parent": "B", "value": 2}
]
},
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
}
]
}
После этого данные становятся иерархическим деревом, пригодным для дальнейших layout-операций.
Treemap отображает дерево через вложенные прямоугольники, где площадь каждого элемента пропорциональна значению.
Ключевая идея:
Vega использует алгоритмы:
В Vega treemap реализуется через трансформацию
treemap:
{
"data": {
"values": [
{"id": "root", "parent": null, "value": 0},
{"id": "A", "parent": "root", "value": 10},
{"id": "B", "parent": "root", "value": 20},
{"id": "C", "parent": "A", "value": 5},
{"id": "D", "parent": "A", "value": 5}
]
},
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "treemap",
"field": "value",
"size": [{"signal": "width"}, {"signal": "height"}],
"method": "squarify"
}
],
"mark": "rect",
"encoding": {
"x": {"field": "x0"},
"x2": {"field": "x1"},
"y": {"field": "y0"},
"y2": {"field": "y1"},
"color": {"field": "depth", "type": "ordinal"}
}
}
После трансформации каждый узел получает координаты:
x0, y0 — верхний левый уголx1, y1 — нижний правый уголdepth — уровень вложенностиchildren — вложенные элементыTreemap эффективен при:
Ограничения:
Vega-Lite не всегда требует ручной работы с layout-трансформациями,
но поддерживает иерархии через hierarchical преобразования
(в зависимости от версии).
Пример treemap в Vega-Lite:
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"id": "A", "parent": null, "value": 10},
{"id": "B", "parent": "A", "value": 5},
{"id": "C", "parent": "A", "value": 8}
]
},
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "treemap",
"field": "value",
"method": "squarify",
"size": [{"signal": "width"}, {"signal": "height"}]
}
],
"mark": "rect",
"encoding": {
"x": {"field": "x0"},
"x2": {"field": "x1"},
"y": {"field": "y0"},
"y2": {"field": "y1"},
"color": {"field": "depth"}
}
}
Dendrogram (дендрограмма) отображает иерархию в виде графа с узлами и связями. В отличие от treemap, здесь сохраняется структура ветвления.
узлы соединяются линиями (links)
положение определяется алгоритмом tree layout
расстояния кодируют глубину
форма может быть:
В Vega используется трансформация tree:
{
"data": {
"values": [
{"id": "A", "parent": null},
{"id": "B", "parent": "A"},
{"id": "C", "parent": "A"},
{"id": "D", "parent": "B"}
]
},
"transform": [
{
"type": "stratify",
"key": "id",
"parentKey": "parent"
},
{
"type": "tree",
"method": "tidy",
"size": [{"signal": "height"}, {"signal": "width"}],
"separation": true
}
]
}
После применения tree каждый узел получает координаты
x, y. Для связей используется генерация
линий:
{
"mark": "rule",
"encoding": {
"x": {"field": "parent.x"},
"y": {"field": "parent.y"},
"x2": {"field": "x"},
"y2": {"field": "y"}
}
}
Узлы:
{
"mark": "circle",
"encoding": {
"x": {"field": "x"},
"y": {"field": "y"},
"size": {"value": 100},
"color": {"field": "depth"}
}
}
Радиальная версия tree layout преобразует декартовы координаты в полярные:
Пример преобразования:
{
"transform": [
{
"type": "formula",
"as": "angle",
"expr": "datum.x / 200 * PI * 2"
},
{
"type": "formula",
"as": "radius",
"expr": "datum.y"
},
{
"type": "formula",
"as": "x",
"expr": "cos(datum.angle) * datum.radius"
},
{
"type": "formula",
"as": "y",
"expr": "sin(datum.angle) * datum.radius"
}
]
}
Treemap:
Dendrogram:
Vega позволяет строить гибридные визуализации:
Для treemap и dendrogram часто используется агрегация:
{
"type": "aggregate",
"groupby": ["parent"],
"ops": ["sum"],
"fields": ["value"],
"as": ["total"]
}
Иерархические алгоритмы опираются на агрегированные значения для определения размеров узлов.
При работе с большими деревьями возникают проблемы:
Оптимизация достигается через:
В Vega иерархия представляет собой расширенный граф:
Эта модель позволяет унифицировать treemap, tree и pack в одной системе трансформаций.