Библиотека D3.js предоставляет механизм преобразования плоских
табличных данных в иерархические структуры через
d3.stratify(), что критически важно для построения
деревьев, кластеров и диаграмм вложенности.
Функция d3.stratify() выполняет трансформацию набора
объектов, содержащих идентификаторы и ссылки на родительские узлы, в
полноценную иерархию в формате d3.hierarchy. Входные данные
при этом остаются плоскими, но приобретают структуру связей
«родитель–потомок».
d3.stratify() строит дерево на основе двух ключевых
правил:
id)parentIdНа выходе формируется объект иерархии, совместимый с алгоритмами
раскладки деревьев (d3.tree, d3.cluster,
d3.pack).
Типичный набор данных:
const data = [
{ id: "root", parentId: "" },
{ id: "a", parentId: "root" },
{ id: "b", parentId: "root" },
{ id: "a1", parentId: "a" },
{ id: "a2", parentId: "a" },
{ id: "b1", parentId: "b" }
];
Особенности:
root не имеет родителяФункция d3.stratify() возвращает конфигурируемый
конструктор иерархии.
const stratify = d3.stratify()
.id(d => d.id)
.parentId(d => d.parentId);
После настройки выполняется преобразование:
const root = stratify(data);
Результат — объект типа d3.hierarchy.
Каждый узел в иерархии содержит:
data — исходный объектparent — ссылка на родителяchildren — массив потомковdepth — глубина узлаheight — высота поддереваid — идентификатор (если задан)Пример обхода:
console.log(root.children);
console.log(root.depth);
При работе d3.stratify() строго проверяются
ограничения:
Если два узла имеют одинаковый id, возникает ошибка.
Каждый parentId должен ссылаться на существующий
id.
Только один узел может иметь пустой parentId.
При нарушении структуры возникают исключения:
Типичный случай ошибки:
Error: multiple roots
d3.stratify() не требует фиксированных названий
полей:
const stratify = d3.stratify()
.id(d => d.key)
.parentId(d => d.parent);
Это позволяет работать с любыми структурами данных, включая API-ответы.
После вызова:
const root = stratify(data);
объект автоматически совместим с алгоритмами раскладки:
const treeLayout = d3.tree().size([width, height]);
treeLayout(root);
Результат содержит координаты x и y для
визуализации.
Типичный сценарий — построение древовидной схемы:
const link = svg.selectAll("path")
.data(root.links())
.enter()
.append("path")
.attr("d", d3.linkHorizontal()
.x(d => d.y)
.y(d => d.x));
Узел-структура, полученная через stratify, напрямую
поддерживает:
root.descendants()root.links()root.each()| Метод | Источник структуры | Назначение |
|---|---|---|
d3.hierarchy() |
вложенные объекты | JSON-деревья |
d3.stratify() |
плоские таблицы | parentId-связи |
d3.stratify() применяется, когда данные приходят из:
Частый сценарий — загрузка через d3.csv:
d3.csv("data.csv").then(data => {
const root = stratify(data);
});
CSV формат:
id,parentId
root,
a,root
b,root
a1,a
a2,a
Перед стратификацией часто выполняется предобработка:
data = data.filter(d => d.id && d.id !== "null");
или нормализация:
data.forEach(d => {
d.parentId = d.parentId || "";
});
После построения иерархии доступны вычисления:
console.log(root.height);
console.log(root.count());
Методы:
count() — количество всех потомковeach() — обход всех узловsort() — сортировка дереваroot.sort((a, b) => b.height - a.height);
Сортировка влияет на:
При работе с тысячами узлов важны:
stratifyПример:
const cached = new Map();
function getHierarchy(data) {
const key = JSON.stringify(data);
if (cached.has(key)) return cached.get(key);
const result = stratify(data);
cached.set(key, result);
return result;
}
После стратификации данные используются в:
d3.tree() — классическое деревоd3.cluster() — компактная кластеризацияd3.pack() — вложенные кругиconst pack = d3.pack().size([500, 500]);
const packed = pack(root);
Важно поддерживать согласованность:
Циклы нарушают модель дерева и приводят к ошибкам исполнения.
Стратификация применяется не только для деревьев, но и для:
После построения иерархии часто применяется масштабирование координат:
const x = d3.scaleLinear().domain([0, root.height]).range([0, width]);
При обновлении данных:
root = stratify(newData);
update(root);
Важно полностью пересчитывать структуру, так как изменения в
parentId могут перераспределить дерево.
Привязка узлов:
const nodes = svg.selectAll("circle")
.data(root.descendants());
Удаление устаревших:
nodes.exit().remove();
d3.stratify() выступает как мост между:
и формирует основу для всех последующих этапов построения дерева внутри D3.js.