or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

hierarchy-construction.mdindex.mdnode-methods.mdpartition-pack.mdtree-layouts.mdtreemap-layouts.md
tile.json

partition-pack.mddocs/

Partition and Circle Packing

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.

Capabilities

Partition Layout

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;
});

Circle Packing Layout

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());

Pack Siblings Utility

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);

Pack Enclose Utility

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);

Coordinate Systems

Partition Coordinates

Partition layouts set rectangular bounds similar to treemaps:

  • x0, y0: Top-left corner
  • x1, y1: Bottom-right corner
  • Each hierarchy level occupies a consistent vertical band
  • Root spans the full width, children subdivide proportionally
// 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 Coordinates

Circle packing layouts set circular properties:

  • x, y: Circle center coordinates
  • r: Circle radius
  • Parent circles contain all child circles
  • Circles are positioned to minimize overlaps
// 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}`);
  }
});

Data Requirements

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);

Advanced Usage

Creating Sunburst Diagrams

// 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;
});

Nested Circle Charts

// 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
  };
});