Claude-skill-registry d3-layouts-hierarchies
Use when creating tree diagrams, force-directed networks, Voronoi diagrams, or hierarchical layouts. Invoke for org charts, node-link diagrams, treemaps, dendrograms, force simulations, spatial indexing, or network visualizations.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/d3-layouts-hierarchies" ~/.claude/skills/majiayu000-claude-skill-registry-d3-layouts-hierarchies && rm -rf "$T"
skills/data/d3-layouts-hierarchies/SKILL.mdD3 Layouts & Hierarchies Expert
Purpose
Expert knowledge of D3's layout algorithms and hierarchical data structures. Covers tree layouts, force-directed graphs, Voronoi diagrams, Delaunay triangulation, quadtrees, and spatial indexing.
When to Use
Invoke this skill when:
- Creating tree diagrams or org charts
- Building force-directed network graphs
- Generating treemaps or circle packing
- Creating dendrograms or phylogenetic trees
- Working with Voronoi diagrams or tessellation
- Implementing Delaunay triangulation
- Building spatial indexes with quadtrees
- Creating sunburst or icicle charts
- Simulating particle systems
- Debugging layout or positioning issues
Documentation Available
Location:
/Users/zach/Documents/cc-skills/docs/d3/
Coverage (177 files):
-
Hierarchy (62 files):
- Tree layouts: tree, cluster
- Space-filling: treemap, partition, pack
- Bundling: bundle
- Hierarchy data structure and methods
- Sorting, filtering, paths, ancestors
-
Force Simulation (47 files):
- Force-directed layout
- Forces: center, collision, links, many-body, X, Y, radial
- Simulation control and optimization
- Custom forces
-
Delaunay/Voronoi (31 files from delaunay):
- Delaunay triangulation
- Voronoi diagrams
- Nearest neighbor queries
- Circumcircles and hull
-
Quadtree (17 files):
- Spatial indexing
- Nearest neighbor search
- Range queries
- Collision detection
-
Voronoi (legacy) (18 files):
- Legacy voronoi implementation
- Polygon generation
Related Skills
- d3-shapes-paths: For rendering tree links and node shapes
- d3-core-data: For hierarchical data transformations
- d3-interaction-animation: For animated layouts
- d3-geo: For geographic network visualization
Best Practices
- Normalize hierarchy data - Use d3.hierarchy() to create structure
- Set appropriate force strengths - Balance forces for stable layouts
- Use collision detection - Prevent node overlap in force layouts
- Optimize simulation - Set alpha decay for convergence
- Use quadtrees for performance - For spatial queries in large datasets
- Set tree separation - Control spacing in tree layouts
- Handle dynamic updates - Reheat simulation for new nodes
- Use canvas for large graphs - SVG performance degrades with many nodes
- Cache layouts - Recompute only when data changes
Examples
Example 1: Tree Layout (Org Chart)
Question: "How do I create an organization chart with D3?"
Response:
import * as d3 from 'd3'; // Sample hierarchical data const data = { name: 'CEO', children: [ { name: 'VP Engineering', children: [ { name: 'Dev Lead', children: [ { name: 'Engineer 1' }, { name: 'Engineer 2' }, ]}, { name: 'QA Lead' }, ], }, { name: 'VP Sales', children: [ { name: 'Sales Rep 1' }, { name: 'Sales Rep 2' }, ], }, ], }; // Create hierarchy const root = d3.hierarchy(data); // Create tree layout const treeLayout = d3.tree() .size([800, 400]) // Width, height .separation((a, b) => (a.parent === b.parent ? 1 : 2) / a.depth); // Compute positions treeLayout(root); // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 500); const g = svg.append('g') .attr('transform', 'translate(0, 50)'); // Draw links g.selectAll('.link') .data(root.links()) .join('path') .attr('class', 'link') .attr('d', d3.linkVertical() .x(d => d.x) .y(d => d.y) ) .attr('fill', 'none') .attr('stroke', '#ccc') .attr('stroke-width', 2); // Draw nodes const node = g.selectAll('.node') .data(root.descendants()) .join('g') .attr('class', 'node') .attr('transform', d => `translate(${d.x}, ${d.y})`); node.append('circle') .attr('r', 5) .attr('fill', d => d.children ? '#555' : '#999'); node.append('text') .attr('dy', -10) .attr('text-anchor', 'middle') .text(d => d.data.name) .style('font-size', '12px'); // Access hierarchy methods console.log('Root node:', root); console.log('Leaves:', root.leaves()); // Nodes without children console.log('Links:', root.links()); // All parent-child links console.log('Depth:', root.height); // Maximum depth console.log('Descendants:', root.descendants()); // All nodes console.log('Ancestors of leaf:', root.leaves()[0].ancestors()); // Path to root
Horizontal Tree (swap x and y):
const treeLayout = d3.tree() .size([400, 800]); // Use linkHorizontal for links const link = d3.linkHorizontal() .x(d => d.y) .y(d => d.x);
References:
- See:
docs/d3/hierarchy/tree.md - See:
docs/d3/hierarchy/hierarchy.md
Example 2: Force-Directed Network Graph
Question: "How do I create an interactive force-directed graph?"
Response:
import * as d3 from 'd3'; // Sample network data const data = { nodes: [ { id: 'A', group: 1 }, { id: 'B', group: 1 }, { id: 'C', group: 2 }, { id: 'D', group: 2 }, { id: 'E', group: 3 }, ], links: [ { source: 'A', target: 'B' }, { source: 'A', target: 'C' }, { source: 'B', target: 'D' }, { source: 'C', target: 'D' }, { source: 'D', target: 'E' }, ], }; // Create SVG const width = 800; const height = 600; const svg = d3.create('svg') .attr('width', width) .attr('height', height); // Create force simulation const simulation = d3.forceSimulation(data.nodes) .force('link', d3.forceLink(data.links) .id(d => d.id) .distance(100) // Link length ) .force('charge', d3.forceManyBody() .strength(-300) // Repulsion between nodes ) .force('center', d3.forceCenter(width / 2, height / 2)) .force('collision', d3.forceCollide() .radius(20) // Prevent overlap ); // Create color scale const color = d3.scaleOrdinal(d3.schemeCategory10); // Draw links const link = svg.append('g') .selectAll('line') .data(data.links) .join('line') .attr('stroke', '#999') .attr('stroke-width', 2) .attr('stroke-opacity', 0.6); // Draw nodes const node = svg.append('g') .selectAll('circle') .data(data.nodes) .join('circle') .attr('r', 10) .attr('fill', d => color(d.group)) .attr('stroke', '#fff') .attr('stroke-width', 2); // Add labels const label = svg.append('g') .selectAll('text') .data(data.nodes) .join('text') .text(d => d.id) .attr('font-size', 12) .attr('dx', 12) .attr('dy', 4); // Add drag behavior const drag = d3.drag() .on('start', (event, d) => { if (!event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; }) .on('drag', (event, d) => { d.fx = event.x; d.fy = event.y; }) .on('end', (event, d) => { if (!event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; }); node.call(drag); // Update positions on each tick simulation.on('tick', () => { link .attr('x1', d => d.source.x) .attr('y1', d => d.source.y) .attr('x2', d => d.target.x) .attr('y2', d => d.target.y); node .attr('cx', d => d.x) .attr('cy', d => d.y); label .attr('x', d => d.x) .attr('y', d => d.y); }); // Stop simulation after convergence simulation.on('end', () => { console.log('Simulation converged'); });
Custom Force (e.g., bounding box):
function boundingBoxForce() { const margin = 20; function force() { data.nodes.forEach(node => { node.x = Math.max(margin, Math.min(width - margin, node.x)); node.y = Math.max(margin, Math.min(height - margin, node.y)); }); } return force; } simulation.force('bounds', boundingBoxForce());
References:
- See:
docs/d3/force/simulation.md - See:
docs/d3/force/forces.md
Example 3: Treemap (Hierarchical Space-Filling)
Question: "How do I create a treemap for file sizes?"
Response:
import * as d3 from 'd3'; // Sample hierarchical data const data = { name: 'root', children: [ { name: 'src', children: [ { name: 'app.js', value: 1200 }, { name: 'utils.js', value: 800 }, ], }, { name: 'assets', children: [ { name: 'logo.png', value: 2400 }, { name: 'bg.jpg', value: 3500 }, ], }, { name: 'docs', children: [ { name: 'readme.md', value: 500 }, ], }, ], }; // Create hierarchy and sum values const root = d3.hierarchy(data) .sum(d => d.value) // Compute value for each node .sort((a, b) => b.value - a.value); // Sort by size // Create treemap layout const treemap = d3.treemap() .size([800, 600]) .padding(2) // Space between cells .round(true); // Compute layout treemap(root); // Create color scale const color = d3.scaleOrdinal(d3.schemeCategory10); // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 600); // Draw cells const cell = svg.selectAll('g') .data(root.leaves()) // Only leaf nodes .join('g') .attr('transform', d => `translate(${d.x0}, ${d.y0})`); cell.append('rect') .attr('width', d => d.x1 - d.x0) .attr('height', d => d.y1 - d.y0) .attr('fill', d => color(d.parent.data.name)) .attr('opacity', 0.6) .attr('stroke', '#fff'); // Add labels cell.append('text') .attr('x', 4) .attr('y', 16) .text(d => d.data.name) .attr('font-size', 10) .attr('fill', 'black'); // Add size labels cell.append('text') .attr('x', 4) .attr('y', 28) .text(d => d3.format('.2s')(d.value)) .attr('font-size', 9) .attr('fill', '#666');
Treemap Tiling Algorithms:
treemap.tile(d3.treemapBinary); // Binary tree treemap.tile(d3.treemapSquarify); // Square aspect ratio (default) treemap.tile(d3.treemapSlice); // Horizontal slices treemap.tile(d3.treemapDice); // Vertical slices treemap.tile(d3.treemapSliceDice); // Alternating
References:
- See:
docs/d3/hierarchy/treemap.md
Example 4: Voronoi Diagram
Question: "How do I create a Voronoi diagram for nearest neighbor?"
Response:
import * as d3 from 'd3'; // Random points const points = Array.from({ length: 50 }, () => ({ x: Math.random() * 800, y: Math.random() * 600, })); // Create Delaunay triangulation const delaunay = d3.Delaunay.from(points, d => d.x, d => d.y); // Create Voronoi diagram const voronoi = delaunay.voronoi([0, 0, 800, 600]); // [xmin, ymin, xmax, ymax] // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 600); // Draw Voronoi cells svg.append('g') .selectAll('path') .data(points) .join('path') .attr('d', (d, i) => voronoi.renderCell(i)) .attr('fill', 'none') .attr('stroke', '#ccc'); // Draw Delaunay triangulation (optional) svg.append('path') .attr('d', delaunay.render()) .attr('fill', 'none') .attr('stroke', 'blue') .attr('opacity', 0.2); // Draw points svg.append('g') .selectAll('circle') .data(points) .join('circle') .attr('cx', d => d.x) .attr('cy', d => d.y) .attr('r', 3) .attr('fill', 'red'); // Find nearest point on click svg.on('click', (event) => { const [mx, my] = d3.pointer(event); const nearestIndex = delaunay.find(mx, my); const nearest = points[nearestIndex]; console.log('Nearest point:', nearest); // Highlight nearest cell svg.selectAll('.highlight').remove(); svg.append('path') .attr('class', 'highlight') .attr('d', voronoi.renderCell(nearestIndex)) .attr('fill', 'yellow') .attr('opacity', 0.5) .attr('stroke', 'red') .attr('stroke-width', 2); }); // Find all neighbors of a point const neighbors = [...delaunay.neighbors(0)]; // Neighbors of point 0 console.log('Neighbors of point 0:', neighbors); // Compute circumcenters const circumcenters = Array.from(delaunay.triangles, (_, i) => { if (i % 3 === 0) { return delaunay.circumcenters.slice(i * 2 / 3, i * 2 / 3 + 2); } }).filter(Boolean);
Delaunay Methods:
- Find nearest point.find(x, y)
- Get neighboring points.neighbors(i)
- Render triangulation as SVG path.render()
- Render convex hull.renderHull()
Voronoi Methods:
- Render cell as SVG path.renderCell(i)
- Get cell vertices.cellPolygon(i)
- Test if point in cell.contains(i, x, y)
References:
- See:
docs/d3/delaunay/
Example 5: Circle Packing
Question: "How do I create a circle packing layout?"
Response:
import * as d3 from 'd3'; const data = { name: 'root', children: [ { name: 'Category A', children: [ { name: 'Item 1', value: 100 }, { name: 'Item 2', value: 200 }, { name: 'Item 3', value: 150 }, ], }, { name: 'Category B', children: [ { name: 'Item 4', value: 300 }, { name: 'Item 5', value: 250 }, ], }, ], }; // Create hierarchy const root = d3.hierarchy(data) .sum(d => d.value) .sort((a, b) => b.value - a.value); // Create pack layout const pack = d3.pack() .size([800, 600]) .padding(3); // Compute layout pack(root); // Create color scale const color = d3.scaleOrdinal(d3.schemeCategory10); // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 600); // Draw circles const node = svg.selectAll('g') .data(root.descendants()) .join('g') .attr('transform', d => `translate(${d.x}, ${d.y})`); node.append('circle') .attr('r', d => d.r) .attr('fill', d => d.children ? 'none' : color(d.parent.data.name)) .attr('opacity', d => d.children ? 0 : 0.6) .attr('stroke', d => d.children ? '#ccc' : '#fff') .attr('stroke-width', d => d.children ? 2 : 1); // Add labels node.append('text') .attr('text-anchor', 'middle') .attr('dy', '0.3em') .text(d => d.children ? d.data.name : '') .attr('font-size', d => Math.min(d.r / 3, 16)) .attr('fill', '#666'); // Add zoom on click node.on('click', (event, d) => { if (!d.children) return; const focus = d; const k = 800 / (focus.r * 2 + 1); svg.transition() .duration(750) .attr('viewBox', `${focus.x - focus.r} ${focus.y - focus.r} ${focus.r * 2} ${focus.r * 2}`); });
Zoomable Sunburst (radial partition):
const partition = d3.partition() .size([2 * Math.PI, radius]); const arc = d3.arc() .startAngle(d => d.x0) .endAngle(d => d.x1) .innerRadius(d => d.y0) .outerRadius(d => d.y1);
References:
- See:
docs/d3/hierarchy/pack.md - See:
docs/d3/hierarchy/partition.md
Common Patterns
Filter Hierarchy
const filtered = root.copy() .each(d => d.children && d.children.filter(c => c.value > 100));
Find Path Between Nodes
function findPath(node1, node2) { const ancestors1 = node1.ancestors(); const ancestors2 = node2.ancestors(); const common = ancestors1.find(a => ancestors2.includes(a)); return [...node1.path(common), ...node2.path(common).reverse()]; }
Reheat Force Simulation
simulation.alpha(1).restart(); // Add new nodes
Spatial Query with Quadtree
const quadtree = d3.quadtree() .x(d => d.x) .y(d => d.y) .addAll(points); // Find points in radius const nearby = []; quadtree.visit((node, x0, y0, x1, y1) => { if (!node.length) { do { const d = node.data; const dx = d.x - mx; const dy = d.y - my; if (dx * dx + dy * dy < radius * radius) { nearby.push(d); } } while (node = node.next); } return x0 > mx + radius || y0 > my + radius || x1 < mx - radius || y1 < my - radius; });
Search Helpers
# Find hierarchy docs grep -r "hierarchy\|tree\|treemap\|pack" /Users/zach/Documents/cc-skills/docs/d3/hierarchy/ # Find force docs grep -r "force\|simulation\|forceLink" /Users/zach/Documents/cc-skills/docs/d3/force/ # Find Delaunay/Voronoi docs grep -r "delaunay\|voronoi\|triangulation" /Users/zach/Documents/cc-skills/docs/d3/delaunay/ # Find quadtree docs grep -r "quadtree\|spatial" /Users/zach/Documents/cc-skills/docs/d3/quadtree/ # List layout modules ls /Users/zach/Documents/cc-skills/docs/d3/hierarchy/ ls /Users/zach/Documents/cc-skills/docs/d3/force/
Common Errors
-
Force simulation not converging: Alpha decay too fast
- Solution: Increase alphaDecay or set alphaTarget
-
Nodes overlap: No collision force
- Solution: Add
.force('collision', d3.forceCollide().radius(r))
- Solution: Add
-
Tree layout cramped: Insufficient separation
- Solution: Adjust
function.separation()
- Solution: Adjust
-
Treemap cells too small: Need minimum size
- Solution: Filter data or use
for spacing.paddingInner()
- Solution: Filter data or use
-
Voronoi artifacts at edges: Bounds not set
- Solution: Set proper bounds in
.voronoi([x0, y0, x1, y1])
- Solution: Set proper bounds in
Performance Tips
- Use Canvas for large graphs - 1000+ nodes perform better in Canvas
- Limit force iterations - Set
higher for faster convergence.alphaMin() - Use quadtrees for collision - O(n log n) instead of O(n²)
- Simplify hierarchy - Prune deep or wide trees
- Cache layout results - Don't recompute on every render
- Use Web Workers - Offload force simulation to worker thread
Notes
- Documentation covers D3 v7 (latest version)
- Force simulation uses velocity Verlet integration
- Delaunay is faster and more robust than legacy Voronoi
- Quadtrees are 2D R-trees for spatial indexing
- Hierarchy methods are chainable and immutable
- Force simulation runs asynchronously
- Treemap tiling affects aspect ratio and readability
- File paths reference local documentation cache
- For latest updates, check https://d3js.org/d3-hierarchy