Visualizations consist of discrete graphical elements like lines, area, arc, symbols etc. We can create all these elements (called Shapes in D3 terminology) using svg:path element. But if you are familiar with the svg:path then you know the pain involved in writing the ‘d’ attribute of the element. A typical example of create an arc may look like this:

“M0,-100A100,100,0,0,1,100,0L0,0Z”

That’s cryptic right? So instead of writing the d attribute manually, D3 provides shape generators which when used generate the d attributes value and then we can simply assign the value to the d attribute and get our desired shape. But to use the shape generators we need to install the d3-shape module first:

## Installing d3-shape

1 |
npm install d3-shape |

or

1 2 |
<script src="https://d3js.org/d3-path.v1.min.js"></script> <script src="https://d3js.org/d3-shape.v1.min.js"></script> |

We are going to cover the following topics related to D3 shapes:

- Using a line generator
- Using line interpolators (curves)
- Using an area generator
- Using area interpolation
- Using an arc generator
- Using a pie generator to draw a pie chart and donut chart
- Implementing arc transition

Each of these topic will have its own demo with full explanation of the code.

## Using a line generator

D3 line generator is one of the most versatile generators. It can be used to create virtually any kind of shape (not only just line). However to make our life easier D3 provides dedicated generators for other shapes like area, arc etc. One important thing to note here is that the line generated with the generator is not the same as svg:line element. The line generator is implemented using svg:path element. The line generator basically generates the d attribute’s value which when used in svg:path element, draws the line. Lets see the line generator in action:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// Sample data points to draw a line // Each data point has an x and y coordinate value var data = [ {x: 0, y: 4}, {x: 1, y: 9}, {x: 2, y: 6}, {x: 4, y: 5}, {x: 6, y: 7}, {x: 7, y: 3}, {x: 9, y: 2} ]; var line = d3.line() .x(function(d) { return xScale(d.x); }) .y(function(d) { return yScale(d.y); }); // Create a path element and set its d attribute value using the line generator created above svgContainer.append("path") .attr("d", line(data)) .attr("fill", "none") .attr("stroke", "red") |

Explanation:

- First we have created a data array containing the (x,y) points which when joined will create the full line.
- In line 13 we used the d3.line() function which returns a line generator and also we specified that the x coordinate will be calculated using the xScale mapping (see the demo code for the scale code) and y coordinate will be calculated using the yScale mapping.
- In line 18 we created a path element in our svg container and set the value of the d attribute using the newly created line generator function y passing the complete data set to the generator.

Lets see the complete code now in the demo shown below (click on the HTML tab to see the code):

So what the line generator basically does is, it generates the d attribute value responsible for putting the data points (x,y) in the coordinate system and then finally joining these points using interpolation. The default interpolation used by D3 is linear(d3.curveLinear). Hence the line segments joining the points are linear. D3 has a bunch of other line interpolators (also known as curve types). Lets explore them next.

## Using line interpolators (curves)

Line interpolators determines how the data points are joined e.g using straight lines or curved lines. Some of the curve types are: d3.curveLinear, d3.curveBasis, d3.curveStep, d3.curveCardinal etc. Check the API Reference for detail description. Here is how to use them:

1 2 3 4 |
var line = d3.line() .x(function(d) { return xScale(d.x); }) .y(function(d) { return yScale(d.y); }) .curve(d3.curveBasis); // Specifies the curve type (interpolation) |

Demo:

*(Click on the buttons to see the different types of interpolation applied to the lines)*

## Using an area generator

Using an area generator is almost similar to using a line generator. The only difference is we specify the lower(x0,y0) and upper(x1,y1) bounds on both x and y axes in area generator as shown below:

1 2 3 4 |
var area = d3.area() .x(function(d) { return xScale(d.x); }) .y0(yScale(0)) .y1(function(d) { return yScale(d.y); }) |

## Using area interpolators

Using area interpolators is same as line interpolators:

1 2 3 4 5 |
var area = d3.area() .x(function(d) { return xScale(d.x); }) .y0(yScale(0)) .y1(function(d) { return yScale(d.y); }) .curve(d3.curveBasis) |

Demo

## Using an arc generator

Using an arc generator we can create a circle, annulus (donut-like), circular sector and annulus sector. Infact we can create arcs of any arbitrary angle. To create an arc generator we need to call the d3.arc() function and set the following parameters:

**innerRadius(r)**: If r > 0, it will create an annulus (donut) arc with the inner radius of the arc as r.**outerRadius(r)**: This sets the outer radius of the arc.**startAngle(angle)**: Sets the start angle of the arc. The angle is in radians with 0 at –*y*(12 o’clock) and positive angles proceeding clockwise.**endAngle(angle)**: Sets the start angle of the arc. The angle is in radians with 0 at –*y*(12 o’clock) and positive angles proceeding clockwise.

Lets use this information to create a sector and an annulus:

Using the arc generator we can create one arc at a time and also specifying startAngle and endAngle manually is also cumbersome. D3 got us cover here. It provides the pie generator for this purpose.

## Using a pie generator

The pie generator itself doesn’t produce any shape directly but it takes a dataset and computes the startAngle and endAngle for us which can then be fed to the arc generator to create arc(s). The pie generator takes an array of flat data and returns an equal sized array of objects where each object contains the datum’s arc angle information. The objects contains the following properties:

- data – the corresponding element in the input data array.
- value – the numeric value of the arc.
- index – the zero-based sorted index of the arc.
- startAngle – the start angle of the arc.
- endAngle – the end angle of the arc.
- padAngle – the pad angle of the arc.

1 2 3 4 |
var data = [1, 2, 1, 5, 6, 8, 10]; var arcs = d3.pie()(data); console.log(arcs); |

The output is shown in the screenshot below:

Now that we have an array of arc slices with its own start angle and end angle we can create a pie chart or donut chart with it as follows:

1 2 3 4 5 6 7 8 9 10 11 12 |
var data = [1, 2, 1, 5, 6, 8, 10]; var arc = d3.arc() .outerRadius(100) .innerRadius(0); var arcs = d3.pie()(data); arcs.forEach(function(d, i) { group.append("path") .attr("d", arc(d)) .attr("fill", color(i)); }); |

Here for each arc object we are creating an arc using the arc generator. The full code is in the demo shown below:

You can create a donut chart by giving the innerRadius() a value > 0. Try this in the JS Bin.

Ok lets wrap us this tutorial by animating the pie chart.

## Implementing arc transition

The arc transition effect cannot be achieved through normal d3 transition. For transitioning an arc we use attrTween(). We need to tween the d attribute of the path element of each arc slice as shown below:

1 2 3 4 5 6 7 8 9 10 11 12 13 |
arcs.forEach(function(d, i) { group.append("path") .attr("fill", color(i)) .transition() .duration(2000) .attrTween("d", function() { var start = {startAngle: 0, endAngle: 0}; var interpolate = d3.interpolate(start, d); return function(t) { return arc(interpolate(t)); }; }) }); |

The attrTween() expects a factory function for a tween function. Here we start our tween from angle 0 and tween both start and end angle and we pass these interpolated angles to create the d attribute.

Demo:

That covers the essential concepts of D3 Shapes.

<< Transitions Layouts >>