Hierarchies
Two ways to describe a tree. A named hierarchy is reusable shorthand — declare geography = [region, country, city] once and reference it by name on either axis. An adjacency list is data
already shaped as a tree: flat rows carrying an id and a parent_id, which the engine nests and
rolls up bottom-up (org charts, bills-of-materials, category trees). Either way the engine builds
the tree and the numbers; the grid just shows it.
Named hierarchies
Section titled “Named hierarchies”A hierarchy name used in rows / columns expands to its ordered level list (fixed order, no
recursion, duplicates dropped). It is a Dash-config convenience; the adapters take the expanded
level list directly as rows.
from dash_tensor_grid import TensorGrid, build_grid
payload = build_grid(sales, { "hierarchies": {"geography": ["region", "country", "city"]}, "rows": ["geography"], # -> region, country, city "measures": {"revenue": "sum", "qty": "sum"}, "formats": {"revenue": "currency:USD"}, "grand_total": True,})TensorGrid(id="grid", row_data=payload["row_data"], column_defs=payload["column_defs"])// Adapters take the expanded levels directly.<TensorGrid data={data} rows={['region', 'country', 'city']} measures={{ revenue: 'sum', qty: 'sum' }} formats={{ revenue: '$0,0' }} grandTotal/>;<TensorGrid :data="data" :rows="['region', 'country', 'city']" :measures="{ revenue: 'sum', qty: 'sum' }" :formats="{ revenue: '$0,0' }" grand-total/>mountTensorGrid(el, { data, rows: ['region', 'country', 'city'], measures: { revenue: 'sum', qty: 'sum' }, formats: { revenue: '$0,0' }, grandTotal: true,});Adjacency-list trees
Section titled “Adjacency-list trees”When the source is a parent-pointer table, nest it with the engine helper. Interior nodes roll up
bottom-up from their descendants (measures); leaves keep their own values. orphans chooses whether
a row with a missing parent becomes a root ('root', default) or is dropped.
from dash_tensor_grid import GridDataEngine, TensorGrid
# Each row: id + parent_id (+ its own measures on the leaves).tree = GridDataEngine(rows).build_adjacency_tree( "id", "parent_id", measures={"headcount": "sum", "budget": "sum"},)column_defs = [ {"accessorKey": "name", "header": "Org unit", "type": "string"}, {"accessorKey": "budget", "header": "Budget", "type": "number", "formatStr": "currency:USD:compact"},]TensorGrid(id="grid", row_data=tree, column_defs=column_defs, initial_state={"expanded": True})import { buildAdjacencyTree } from '@tensorgrid/core';
// The nested { id, subRows } forest — the same row-model shape the grid renders.const tree = buildAdjacencyTree(rows, 'id', 'parent_id', { measures: { headcount: 'sum', budget: 'sum' }, labelField: 'name',});<script setup lang="ts">import { buildAdjacencyTree } from '@tensorgrid/core';
const tree = buildAdjacencyTree(rows, 'id', 'parent_id', { measures: { headcount: 'sum', budget: 'sum' }, labelField: 'name',});</script>import { buildAdjacencyTree } from '@tensorgrid/core';
const tree = buildAdjacencyTree(rows, 'id', 'parent_id', { measures: { headcount: 'sum', budget: 'sum' }, labelField: 'name',});- Named hierarchies are fixed-order and non-recursive. A name that matches a
hierarchieskey expands to its levels; any other name passes through, sorows: [geography, segment]mixes freely. Duplicate columns are dropped (first occurrence wins). build_adjacency_tree/buildAdjacencyTreeroll interior nodes up withsum/mean/min/max/countper field;labelFieldcopies a column onto each node aslabel; the output is JSON-safe and byte-identical between the engine and the core port.- Pair a deep hierarchy with the virtualized grid when the tree gets large, or an auto-group column to give the hierarchy its own dedicated column.