Two complementary layout algorithms: partition creates "icicle" adjacency diagrams using rectangles to show topology, while circle packing creates enclosure diagrams with nested circles for hierarchical containment.
Creates partition (icicle) layouts where hierarchical relationships are shown through adjacency of rectangles. Each level of the hierarchy occupies a consistent band.
/**
* Creates a partition layout function
* @returns Partition layout function with configuration methods
*/
function partition();
interface PartitionLayout {
/** Apply partition layout to hierarchy root */
(root: Node): Node;
/** Get/set the layout size [width, height] */
size(size?: [number, number]): PartitionLayout | [number, number];
/** Get/set coordinate rounding */
round(round?: boolean): PartitionLayout | boolean;
/** Get/set padding between rectangles */
padding(padding?: number): PartitionLayout | number;
}Usage Examples:
import { hierarchy, partition } from "d3-hierarchy";
const data = {
name: "root",
children: [
{ name: "A", value: 25 },
{ name: "B", value: 50, children: [
{ name: "B1", value: 20 },
{ name: "B2", value: 30 }
]},
{ name: "C", value: 25 }
]
};
// Basic partition layout
const root = hierarchy(data)
.sum(d => d.value)
.sort((a, b) => b.value - a.value);
const partitionLayout = partition().size([400, 200]);
const partitionRoot = partitionLayout(root);
// Access rectangular coordinates
partitionRoot.each(node => {
console.log(node.data.name, node.x0, node.y0, node.x1, node.y1);
const width = node.x1 - node.x0;
const height = node.y1 - node.y0;
});
// Partition with padding and rounding
const styledPartition = partition()
.size([600, 300])
.round(true)
.padding(1);
const styledRoot = styledPartition(root.copy());
// Vertical partition (sunburst preparation)
const verticalPartition = partition().size([2 * Math.PI, 100]);
const radialRoot = verticalPartition(root.copy());
// Convert to polar coordinates for sunburst
radialRoot.each(node => {
const startAngle = node.x0;
const endAngle = node.x1;
const innerRadius = node.y0;
const outerRadius = node.y1;
// Store polar coordinates
node.startAngle = startAngle;
node.endAngle = endAngle;
node.innerRadius = innerRadius;
node.outerRadius = outerRadius;
});Creates circle packing layouts where hierarchical containment is represented by nested circles. Uses Wang et al.'s front-chain packing algorithm.
/**
* Creates a circle packing layout function
* @returns Pack layout function with configuration methods
*/
function pack();
interface PackLayout {
/** Apply circle packing layout to hierarchy root */
(root: Node): Node;
/** Get/set the radius accessor function */
radius(radius?: (node: Node) => number): PackLayout | Function | null;
/** Get/set the layout size [width, height] */
size(size?: [number, number]): PackLayout | [number, number];
/** Get/set padding between circles */
padding(padding?: number | ((node: Node) => number)): PackLayout | number | Function;
}Usage Examples:
import { hierarchy, pack } from "d3-hierarchy";
// Basic circle packing
const root = hierarchy(data)
.sum(d => d.value)
.sort((a, b) => b.value - a.value);
const packLayout = pack().size([400, 400]);
const packedRoot = packLayout(root);
// Access circle coordinates
packedRoot.each(node => {
console.log(node.data.name, `center: (${node.x}, ${node.y}), radius: ${node.r}`);
});
// Circle packing with custom radius function
const customPack = pack()
.radius(node => Math.sqrt(node.value) * 2)
.size([500, 500]);
const customRoot = customPack(root.copy());
// Circle packing with padding
const paddedPack = pack()
.padding(3) // 3px padding between circles
.size([400, 400]);
const paddedRoot = paddedPack(root.copy());
// Dynamic padding based on hierarchy depth
const dynamicPack = pack()
.padding(node => node.depth * 2)
.size([400, 400]);
const dynamicRoot = dynamicPack(root.copy());Packs circles as siblings without hierarchical nesting, useful for creating bubble charts.
/**
* Packs an array of circles as siblings using the front-chain algorithm
* @param circles - Array of circles with 'r' property, modified in-place
* @returns The input circles array with computed x,y positions
*/
function packSiblings(circles);Usage Examples:
import { packSiblings } from "d3-hierarchy";
// Pack circles as siblings
const circles = [
{ r: 10, name: "A" },
{ r: 20, name: "B" },
{ r: 15, name: "C" },
{ r: 5, name: "D" }
];
packSiblings(circles);
// Access computed positions
circles.forEach(circle => {
console.log(`${circle.name}: center (${circle.x}, ${circle.y}), radius ${circle.r}`);
});
// Create bubble chart data
const bubbleData = data.children.map(d => ({ r: Math.sqrt(d.value), ...d }));
packSiblings(bubbleData);Computes the smallest circle that encloses a set of circles.
/**
* Computes the smallest enclosing circle for an array of circles
* @param circles - Array of circles with x, y, r properties
* @returns Enclosing circle with x, y, r properties
*/
function packEnclose(circles);Usage Examples:
import { packEnclose } from "d3-hierarchy";
// Find enclosing circle
const circles = [
{ x: 0, y: 0, r: 10 },
{ x: 20, y: 0, r: 15 },
{ x: 10, y: 15, r: 5 }
];
const enclosingCircle = packEnclose(circles);
console.log(`Enclosing circle: center (${enclosingCircle.x}, ${enclosingCircle.y}), radius ${enclosingCircle.r}`);
// Use with packed siblings
const siblings = [{ r: 10 }, { r: 15 }, { r: 8 }];
packSiblings(siblings);
const bounds = packEnclose(siblings);Partition layouts set rectangular bounds similar to treemaps:
x0, y0: Top-left cornerx1, y1: Bottom-right corner// Partition coordinate analysis
partitionRoot.each(node => {
const width = node.x1 - node.x0;
const height = node.y1 - node.y0;
const level = node.depth;
console.log(`Level ${level}: ${width} × ${height}`);
});Circle packing layouts set circular properties:
x, y: Circle center coordinatesr: Circle radius// Circle packing coordinate analysis
packedRoot.each(node => {
if (node.children) {
console.log(`${node.data.name}: container circle at (${node.x}, ${node.y}) with radius ${node.r}`);
} else {
console.log(`${node.data.name}: leaf circle at (${node.x}, ${node.y}) with radius ${node.r}`);
}
});Both partition and pack layouts require numeric values:
// Compute values before layout
const root = hierarchy(data)
.sum(d => d.value || 1) // Use 1 as default for nodes without values
.sort((a, b) => b.value - a.value); // Optional sorting
// Apply layout
const result = partition().size([400, 200])(root);
// or
const result = pack().size([400, 400])(root);// Partition with polar coordinates for sunburst
const sunburstData = partition()
.size([2 * Math.PI, 100])(root);
sunburstData.each(node => {
// Convert to arc properties for D3 arc generator
node.startAngle = node.x0;
node.endAngle = node.x1;
node.innerRadius = node.y0;
node.outerRadius = node.y1;
});// Circle packing with custom styling based on depth
const styledPack = pack()
.padding(2)
.size([400, 400])(root);
styledPack.each(node => {
// Apply different styles based on hierarchy level
node.style = {
fill: node.children ? 'transparent' : `hsl(${node.depth * 60}, 50%, 50%)`,
stroke: node.children ? '#333' : 'none',
strokeWidth: node.depth + 1
};
});