Skip to content

D3.js - Shapes API

D3.js provides a powerful module, d3-shape, for generating SVG path data for various graphical shapes like arcs (for pie/donut charts), lines (for line charts), and areas (for area charts). These shape generators take data and return the string value for an SVG <path> element’s d attribute.

To use the D3.js Shapes API, you need to include the D3.js library in your HTML file. The simplest way is to use the full D3 bundle from a CDN, which includes d3-shape and its dependency d3-path.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3.js Shapes API Example</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<svg id="visualization" width="400" height="300"></svg>
<script>
// Your D3.js code using d3-shape will go here
</script>
</body>
</html>

D3.js offers several shape generators. Let’s explore some of the prominent ones.

The arc generator (d3.arc()) is used to produce the path data for circular or annular sectors, commonly used in pie charts and donut charts.

  • d3.arc(): Creates a new arc generator with default settings.
  • arc(dataObject): Generates the path string for an arc. The dataObject typically needs properties like innerRadius, outerRadius, startAngle, and endAngle. Example:
  • { innerRadius: 0, outerRadius: 100, startAngle: 0, endAngle: Math.PI / 2 } would define a quarter circle.
  • arc.innerRadius([radius]): Sets or gets the inner radius. radius can be a constant or a function that receives data and returns a value. Default accessor: function innerRadius(d) { return d.innerRadius; }.
  • arc.outerRadius([radius]): Sets or gets the outer radius. Default accessor: function outerRadius(d) { return d.outerRadius; }.
  • arc.startAngle([angle]): Sets or gets the start angle (in radians). Default accessor: function startAngle(d) { return d.startAngle; }.
  • arc.endAngle([angle]): Sets or gets the end angle (in radians). Default accessor: function endAngle(d) { return d.endAngle; }.
  • arc.padAngle([angle]): Sets or gets the padding angle between arcs (useful for separating pie slices). Default accessor: function padAngle(d) { return d && d.padAngle; }.
  • arc.cornerRadius([radius]): Sets or gets the corner radius, which rounds the corners of the arc. Helpful for stylistic effects.
  • arc.centroid(dataObject): Computes the midpoint [x, y] of the arc’s centerline. Useful for placing labels.

Example usage:

const arcGenerator = d3.arc()
.innerRadius(50)
.outerRadius(100)
.startAngle(0)
.endAngle(Math.PI / 2); // A quarter donut segment
const pathData = arcGenerator(); // Generates path string for a single arc with fixed values
// Or, if data-bound:
// const pathData = arcGenerator(dataObjectForArc);
d3.select("#visualization").append("path")
.attr("d", pathData)
.attr("transform", "translate(150, 150)") // Position the arc
.attr("fill", "steelblue");

The pie generator (d3.pie()) doesn’t draw anything itself. Instead, it takes an array of data and computes the necessary start and end angles for each slice of a pie chart. The output of d3.pie() is then typically passed to d3.arc() to generate the actual path data for each slice.

  • d3.pie(): Constructs a new pie generator with default settings.
  • pie(dataArray): Computes angles for the given dataArray. It returns an array of objects, where each object represents a slice and includes:
  • data: The original input datum for that slice.
  • value: The numeric value of the slice (used for angle calculation).
  • index: The original index of the datum.
  • startAngle: The calculated start angle for the slice.
  • endAngle: The calculated end angle for the slice.
  • padAngle: The padding angle (if set on the pie generator).
  • pie.value([accessor]): Sets or gets the accessor function that extracts the numerical value from each data element. Default: function value(d) { return d; }.
  • pie.sort([comparator]): Sets or gets a comparator function to sort slices by their original data object. Set to null to preserve input order.
  • pie.sortValues([comparator]): Sets or gets a comparator function to sort slices by their computed numeric value. Set to null to preserve input order. Default is descending.
  • pie.startAngle([angle]): Sets or gets the overall start angle for the pie (e.g., 0 for 12 o’clock).
  • pie.endAngle([angle]): Sets or gets the overall end angle for the pie (e.g., 2 * Math.PI for a full circle).
  • pie.padAngle([angle]): Sets or gets the angle to separate slices.

Example usage with d3.arc:

const dataset = [10, 20, 30, 40];
const pieGenerator = d3.pie();
const arcData = pieGenerator(dataset);
// arcData is now an array of objects with startAngle, endAngle, etc.
// e.g., [{data: 10, value: 10, index: 0, startAngle: ..., endAngle: ..., padAngle:...}, ...]
const arcGeneratorForPie = d3.arc().innerRadius(0).outerRadius(100);
d3.select("#visualization")
.selectAll(".pieSlice")
.data(arcData)
.enter()
.append("path")
.attr("class", "pieSlice")
.attr("d", arcGeneratorForPie)
.attr("fill", (d, i) => d3.schemeCategory10[i])
.attr("transform", "translate(150, 150)");

The line generator (d3.line()) is used to produce path data for polylines, essential for line charts.

  • d3.line(): Creates a new line generator.
  • line(dataArray): Generates the path string for a line, given an array of data points. Each point in dataArray usually has an x and y component.
  • line.x([accessor]): Sets or gets the accessor for the x-coordinate of each point. Default: function x(d) { return d[0]; } (assumes points are [x, y] arrays).
  • line.y([accessor]): Sets or gets the accessor for the y-coordinate of each point. Default: function y(d) { return d[1]; }.
  • line.defined([accessor]): Sets or gets an accessor to control whether a point is defined. If a point is undefined, the line will have a break. Default: function defined() { return true; }.
  • line.curve([curveType]): Sets or gets the interpolation strategy for drawing the line between points (e.g., d3.curveLinear, d3.curveBasis, d3.curveStep).
  • line.context([canvasContext]): Sets the rendering context if drawing directly to a Canvas 2D API (less common for SVG).

Example usage:

const lineData = [ [0, 80], [100, 100], [200, 30], [300, 50], [400, 40] ];
const lineGenerator = d3.line(); // Uses default x and y accessors
// Or, if data is an array of objects:
// const lineData = [ {xVal:0, yVal:80}, {xVal:100, yVal:100}, ... ];
// const lineGenerator = d3.line()
// .x(d => d.xVal)
// .y(d => d.yVal);
const pathString = lineGenerator(lineData);
d3.select("#visualization").append("path")
.attr("d", pathString)
.attr("fill", "none")
.attr("stroke", "green");

d3.lineRadial() is similar to d3.line(), but it generates lines in polar coordinates (angle and radius) instead of Cartesian coordinates (x and y). Useful for radar charts or spiral plots.

  • d3.lineRadial(): Creates a new radial line generator.
  • lineRadial.angle([accessor]): Sets or gets the accessor for the angle (in radians).
  • lineRadial.radius([accessor]): Sets or gets the accessor for the radius (distance from origin).

These shape generators are fundamental tools for creating common chart types in D3.js by simplifying the construction of complex SVG path data.