Skip to content
d3-shapes-paths logo

D3 Shapes & Paths Expert

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.

SKILL.md

Full skill instructions

D3 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:

  • curveLinear - Straight lines (default)
  • curveMonotoneX - Smooth, no overshoot
  • curveCatmullRom - Smooth, passes through points
  • curveBasis - Smooth B-spline
  • curveStep - Step function

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:

  • stackOrderNone - Original order
  • stackOrderAscending - Smallest on top
  • stackOrderDescending - Largest on top
  • stackOrderInsideOut - Largest in middle

Stack Offsets:

  • stackOffsetNone - Zero baseline
  • stackOffsetExpand - Normalize to [0, 1]
  • stackOffsetSilhouette - Center around zero
  • stackOffsetWiggle - Minimize changes in slope

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:

  • symbolCircle - Circle
  • symbolSquare - Square
  • symbolTriangle - Upward triangle
  • symbolStar - Five-pointed star
  • symbolDiamond - Diamond
  • symbolCross - Plus sign
  • symbolWye - Y shape

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 transform="translate(cx, cy)" to group
  • Gaps in line: Null/​undefined values in data

    • Solution: Set .defined(d => d.value != null)
  • Stack negative values: stackOffsetNone doesn't handle negatives

    • Solution: Use stackOffsetDiverging for +/​- values

Performance Tips

  1. Use .curve(d3.curveLinear) - Fastest rendering
  2. Simplify paths - Use fewer data points for large datasets
  3. Avoid recomputing generators - Create once, reuse
  4. Use context rendering - For Canvas instead of SVG
  5. Batch path updates - Use .datum() instead of .data() when possible
  6. 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

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View