Claude-skill-registry d3-shapes-paths
Use when creating SVG shapes, paths, or generators for charts. Invoke for line/area/arc generators, curves, symbols, pie/donut charts, stacks, ribbons, or path manipulation operations.
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-shapes-paths" ~/.claude/skills/majiayu000-claude-skill-registry-d3-shapes-paths && rm -rf "$T"
skills/data/d3-shapes-paths/SKILL.mdD3 Shapes & Paths Expert
Purpose
Expert knowledge of D3's shape generators and path manipulation. Covers line, area, arc, pie, symbol, stack, ribbon generators, curve interpolation, and SVG path construction.
When to Use
Invoke this skill when:
- Creating line or area charts
- Building pie or donut charts
- Generating arc segments (gauges, progress indicators)
- Creating stacked charts (bar, area)
- Working with curve interpolation
- Drawing symbols (circles, squares, diamonds)
- Building chord diagrams
- Generating contour plots
- Manipulating SVG paths
- Debugging shape rendering issues
Documentation Available
Location:
/Users/zach/Documents/cc-skills/docs/d3/
Coverage (203 files):
-
Shapes (146 files):
- Lines: line generator, curve interpolation
- Areas: area generator, radial areas
- Arcs: arc generator, pie layout
- Symbols: symbol types and custom symbols
- Stacks: stack layout, stack order
- Links: link generators (orthogonal, radial)
- Curves: 15+ interpolation types
-
Paths (12 files):
- Path construction and serialization
- Path data parsing
- Geometric operations
-
Contours (17 files):
- Contour generation
- Density estimation
- Marching squares algorithm
-
Chords (22 files):
- Chord layout
- Ribbon generator
- Chord diagrams
-
Polygons (6 files):
- Polygon operations
- Hull, centroid, area calculations
Related Skills
- d3-core-data: For scales used with shapes
- d3-geo: For geographic path generators
- d3-interaction-animation: For animating shapes
- d3-layouts-hierarchies: For tree/network shapes
Best Practices
- Define accessors consistently - Use x/y accessors for data binding
- Use curve interpolators - Choose appropriate curve type for data
- Handle null data - Set .defined() to skip gaps in lines
- Use radial variants - For circular/polar charts
- Optimize path rendering - Simplify paths for large datasets
- Set arc padding - Add spacing in pie charts
- Use stack keys - Define series for stacked charts
- Apply proper transforms - Translate arcs to center
Examples
Example 1: Line Chart with Multiple Series
Question: "How do I create a multi-series line chart?"
Response:
import * as d3 from 'd3'; // Sample data const data = [ { date: new Date('2024-01-01'), series1: 30, series2: 20 }, { date: new Date('2024-01-02'), series1: 45, series2: 35 }, { date: new Date('2024-01-03'), series1: 40, series2: 30 }, { date: new Date('2024-01-04'), series1: null, series2: 40 }, // Gap in series1 { date: new Date('2024-01-05'), series1: 60, series2: 50 }, ]; // Create scales const xScale = d3.scaleTime() .domain(d3.extent(data, d => d.date)) .range([0, 800]); const yScale = d3.scaleLinear() .domain([0, d3.max(data, d => Math.max(d.series1 || 0, d.series2))]) .range([400, 0]) .nice(); // Create line generator const line = d3.line() .x(d => xScale(d.date)) .y(d => yScale(d.value)) .curve(d3.curveMonotoneX) // Smooth curve .defined(d => d.value != null); // Skip null values // Transform data for each series const series1Data = data.map(d => ({ date: d.date, value: d.series1 })); const series2Data = data.map(d => ({ date: d.date, value: d.series2 })); // Generate path data const path1 = line(series1Data); const path2 = line(series2Data); // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 400); // Add lines svg.append('path') .attr('d', path1) .attr('fill', 'none') .attr('stroke', 'steelblue') .attr('stroke-width', 2); svg.append('path') .attr('d', path2) .attr('fill', 'none') .attr('stroke', 'orange') .attr('stroke-width', 2); // Add axes const xAxis = d3.axisBottom(xScale); const yAxis = d3.axisLeft(yScale); svg.append('g') .attr('transform', 'translate(0, 400)') .call(xAxis); svg.append('g') .call(yAxis);
Curve Types:
- Straight lines (default)curveLinear
- Smooth, no overshootcurveMonotoneX
- Smooth, passes through pointscurveCatmullRom
- Smooth B-splinecurveBasis
- Step functioncurveStep
References:
- See:
docs/d3/shape/line.md - See:
docs/d3/shape/curve.md
Example 2: Area Chart with Gradient
Question: "How do I create an area chart with gradient fill?"
Response:
import * as d3 from 'd3'; const data = [ { x: 0, y0: 0, y1: 30 }, { x: 1, y0: 0, y1: 45 }, { x: 2, y0: 0, y1: 40 }, { x: 3, y0: 0, y1: 60 }, { x: 4, y0: 0, y1: 50 }, ]; // Create scales const xScale = d3.scaleLinear() .domain([0, 4]) .range([0, 800]); const yScale = d3.scaleLinear() .domain([0, 60]) .range([400, 0]); // Create area generator const area = d3.area() .x(d => xScale(d.x)) .y0(d => yScale(d.y0)) // Baseline .y1(d => yScale(d.y1)) // Top line .curve(d3.curveMonotoneX); // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 400); // Define gradient const gradient = svg.append('defs') .append('linearGradient') .attr('id', 'area-gradient') .attr('x1', '0%') .attr('y1', '0%') .attr('x2', '0%') .attr('y2', '100%'); gradient.append('stop') .attr('offset', '0%') .attr('stop-color', 'steelblue') .attr('stop-opacity', 0.8); gradient.append('stop') .attr('offset', '100%') .attr('stop-color', 'steelblue') .attr('stop-opacity', 0.1); // Add area svg.append('path') .datum(data) .attr('d', area) .attr('fill', 'url(#area-gradient)'); // Add top line const line = d3.line() .x(d => xScale(d.x)) .y(d => yScale(d.y1)) .curve(d3.curveMonotoneX); svg.append('path') .datum(data) .attr('d', line) .attr('fill', 'none') .attr('stroke', 'steelblue') .attr('stroke-width', 2);
Radial Area (for circular charts):
const radialArea = d3.areaRadial() .angle(d => angleScale(d.angle)) .innerRadius(d => radiusScale(d.inner)) .outerRadius(d => radiusScale(d.outer));
References:
- See:
docs/d3/shape/area.md - See:
docs/d3/shape/radial.md
Example 3: Pie and Donut Charts
Question: "How do I create a pie chart with labels?"
Response:
import * as d3 from 'd3'; const data = [ { category: 'A', value: 30 }, { category: 'B', value: 80 }, { category: 'C', value: 45 }, { category: 'D', value: 60 }, ]; // Create pie layout const pie = d3.pie() .value(d => d.value) .sort(null) // Keep original order .padAngle(0.02); // Spacing between slices // Create arc generator const arc = d3.arc() .innerRadius(0) // Use innerRadius > 0 for donut .outerRadius(150); // Arc for labels (slightly outside) const labelArc = d3.arc() .innerRadius(170) .outerRadius(170); // Color scale const color = d3.scaleOrdinal() .domain(data.map(d => d.category)) .range(d3.schemeCategory10); // Create SVG const svg = d3.create('svg') .attr('width', 400) .attr('height', 400); const g = svg.append('g') .attr('transform', 'translate(200, 200)'); // Center // Generate pie data const pieData = pie(data); // Add arcs g.selectAll('path') .data(pieData) .join('path') .attr('d', arc) .attr('fill', d => color(d.data.category)) .attr('stroke', 'white') .attr('stroke-width', 2); // Add labels g.selectAll('text') .data(pieData) .join('text') .attr('transform', d => `translate(${labelArc.centroid(d)})`) .attr('text-anchor', 'middle') .text(d => d.data.category); // Add percentage labels g.selectAll('.percentage') .data(pieData) .join('text') .attr('class', 'percentage') .attr('transform', d => `translate(${arc.centroid(d)})`) .attr('text-anchor', 'middle') .attr('fill', 'white') .attr('font-weight', 'bold') .text(d => { const percent = ((d.endAngle - d.startAngle) / (2 * Math.PI) * 100).toFixed(1); return `${percent}%`; });
Donut Chart (add inner radius):
const arc = d3.arc() .innerRadius(80) // Creates donut hole .outerRadius(150);
Corner Radius (rounded corners):
const arc = d3.arc() .innerRadius(80) .outerRadius(150) .cornerRadius(5);
References:
- See:
docs/d3/shape/pie.md - See:
docs/d3/shape/arc.md
Example 4: Stacked Area Chart
Question: "How do I create a stacked area chart?"
Response:
import * as d3 from 'd3'; const data = [ { date: new Date('2024-01-01'), apples: 30, bananas: 20, oranges: 10 }, { date: new Date('2024-01-02'), apples: 45, bananas: 35, oranges: 15 }, { date: new Date('2024-01-03'), apples: 40, bananas: 30, oranges: 20 }, { date: new Date('2024-01-04'), apples: 60, bananas: 40, oranges: 25 }, ]; // Define stack keys (series) const keys = ['apples', 'bananas', 'oranges']; // Create stack layout const stack = d3.stack() .keys(keys) .order(d3.stackOrderNone) // Keep original order .offset(d3.stackOffsetNone); // Start from zero // Generate stack data const stackedData = stack(data); // [ // [[0, 30], [0, 45], ...], // apples layer // [[30, 50], [45, 80], ...], // bananas layer // [[50, 60], [80, 95], ...], // oranges layer // ] // Create scales const xScale = d3.scaleTime() .domain(d3.extent(data, d => d.date)) .range([0, 800]); const yScale = d3.scaleLinear() .domain([0, d3.max(stackedData[stackedData.length - 1], d => d[1])]) .range([400, 0]) .nice(); // Create area generator const area = d3.area() .x(d => xScale(d.data.date)) .y0(d => yScale(d[0])) // Bottom of stack .y1(d => yScale(d[1])) // Top of stack .curve(d3.curveMonotoneX); // Color scale const color = d3.scaleOrdinal() .domain(keys) .range(d3.schemeCategory10); // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 400); // Add layers svg.selectAll('path') .data(stackedData) .join('path') .attr('d', area) .attr('fill', d => color(d.key)) .attr('stroke', 'white') .attr('stroke-width', 1); // Add legend const legend = svg.append('g') .attr('transform', 'translate(700, 20)'); legend.selectAll('rect') .data(keys) .join('rect') .attr('y', (d, i) => i * 25) .attr('width', 20) .attr('height', 20) .attr('fill', d => color(d)); legend.selectAll('text') .data(keys) .join('text') .attr('x', 25) .attr('y', (d, i) => i * 25 + 15) .text(d => d);
Stack Orders:
- Original orderstackOrderNone
- Smallest on topstackOrderAscending
- Largest on topstackOrderDescending
- Largest in middlestackOrderInsideOut
Stack Offsets:
- Zero baselinestackOffsetNone
- Normalize to [0, 1]stackOffsetExpand
- Center around zerostackOffsetSilhouette
- Minimize changes in slopestackOffsetWiggle
References:
- See:
docs/d3/shape/stack.md
Example 5: Symbols and Custom Shapes
Question: "How do I use D3 symbols for scatter plots?"
Response:
import * as d3 from 'd3'; const data = [ { x: 30, y: 20, type: 'A' }, { x: 50, y: 80, type: 'B' }, { x: 80, y: 50, type: 'A' }, { x: 120, y: 90, type: 'C' }, ]; // Create scales const xScale = d3.scaleLinear() .domain([0, 150]) .range([0, 800]); const yScale = d3.scaleLinear() .domain([0, 100]) .range([400, 0]); // Symbol types const symbolTypes = [ d3.symbolCircle, d3.symbolSquare, d3.symbolTriangle, d3.symbolStar, d3.symbolDiamond, d3.symbolCross, ]; // Symbol scale const symbolScale = d3.scaleOrdinal() .domain(['A', 'B', 'C']) .range([d3.symbolCircle, d3.symbolSquare, d3.symbolTriangle]); // Create symbol generator const symbol = d3.symbol() .size(200); // Area in square pixels // Create SVG const svg = d3.create('svg') .attr('width', 800) .attr('height', 400); // Add symbols svg.selectAll('path') .data(data) .join('path') .attr('d', d => { symbol.type(symbolScale(d.type)); return symbol(); }) .attr('transform', d => `translate(${xScale(d.x)}, ${yScale(d.y)})`) .attr('fill', 'steelblue') .attr('stroke', 'white') .attr('stroke-width', 2);
Available Symbol Types:
- CirclesymbolCircle
- SquaresymbolSquare
- Upward trianglesymbolTriangle
- Five-pointed starsymbolStar
- DiamondsymbolDiamond
- Plus signsymbolCross
- Y shapesymbolWye
Custom Symbol:
const customSymbol = { draw(context, size) { const r = Math.sqrt(size / 5) / 2; context.moveTo(-3 * r, -r); context.lineTo(-r, -r); context.lineTo(-r, -3 * r); context.lineTo(r, -3 * r); context.lineTo(r, -r); context.lineTo(3 * r, -r); context.lineTo(3 * r, r); context.lineTo(r, r); context.lineTo(r, 3 * r); context.lineTo(-r, 3 * r); context.lineTo(-r, r); context.lineTo(-3 * r, r); context.closePath(); }, }; const symbol = d3.symbol() .type(customSymbol) .size(200);
References:
- See:
docs/d3/shape/symbol.md
Common Patterns
Responsive Line Chart
const line = d3.line() .x(d => xScale(d.x)) .y(d => yScale(d.y)) .curve(d3.curveMonotoneX); svg.append('path') .datum(data) .attr('d', line) .attr('fill', 'none') .attr('stroke', 'steelblue') .attr('stroke-width', 2);
Arc with Hover Effect
const arc = d3.arc() .innerRadius(80) .outerRadius(150); const arcHover = d3.arc() .innerRadius(80) .outerRadius(160); // Larger svg.selectAll('path') .on('mouseenter', function() { d3.select(this).transition() .attr('d', arcHover); }) .on('mouseleave', function() { d3.select(this).transition() .attr('d', arc); });
Link Generators (for node diagrams)
const link = d3.linkHorizontal() .x(d => d.x) .y(d => d.y); const linkData = { source: { x: 0, y: 100 }, target: { x: 200, y: 150 }, }; svg.append('path') .attr('d', link(linkData)) .attr('fill', 'none') .attr('stroke', 'black');
Search Helpers
# Find line/area docs grep -r "line\|area\|curve" /Users/zach/Documents/cc-skills/docs/d3/shape/ # Find pie/arc docs grep -r "pie\|arc\|donut" /Users/zach/Documents/cc-skills/docs/d3/shape/ # Find stack docs grep -r "stack\|layer" /Users/zach/Documents/cc-skills/docs/d3/shape/ # Find symbol docs grep -r "symbol\|scatter" /Users/zach/Documents/cc-skills/docs/d3/shape/ # Find path operations grep -r "path\|serialize" /Users/zach/Documents/cc-skills/docs/d3/path/ # List shape generators ls /Users/zach/Documents/cc-skills/docs/d3/shape/
Common Errors
-
Path not rendering: Check scale domains match data range
- Solution: Use d3.extent() to compute correct domain
-
Area chart inverted: Y scale range is backwards
- Solution: Set range as [height, 0] (SVG y grows downward)
-
Pie chart off-center: Missing transform translate
- Solution: Add
to grouptransform="translate(cx, cy)"
- Solution: Add
-
Gaps in line: Null/undefined values in data
- Solution: Set
.defined(d => d.value != null)
- Solution: Set
-
Stack negative values: stackOffsetNone doesn't handle negatives
- Solution: Use stackOffsetDiverging for +/- values
Performance Tips
- Use .curve(d3.curveLinear) - Fastest rendering
- Simplify paths - Use fewer data points for large datasets
- Avoid recomputing generators - Create once, reuse
- Use context rendering - For Canvas instead of SVG
- Batch path updates - Use .datum() instead of .data() when possible
- Optimize arc rendering - Use fewer padAngle for large datasets
Notes
- Documentation covers D3 v7 (latest version)
- All generators support both SVG and Canvas contexts
- Curve interpolators are interchangeable across line/area generators
- Pie layout computes startAngle and endAngle for each datum
- Stack layout adds [y0, y1] arrays to each data point
- Symbol size is in square pixels (area, not radius)
- Path generators are immutable - methods return new generators
- File paths reference local documentation cache
- For latest updates, check https://d3js.org/d3-shape