Visualisation with D3.js v7

A practical book on visualisation with D3.js version 7 that shows you how to create visualisations from the ground up.

Get the book

Path Construction with 2D Arrays

Highlight

Whilst you could say that it's possible to draw a zigzag using multiple rect elements at different positions and rotations, it is certainly an infeasible and inefficient exercise. This is where the SVG path element comes in. A path describes an outline of some shape that can be filled and/or stroked.

Preamble

Let's get access to the D3.js library so that we can begin. In this case, we'll be including the library using the HTML <script> tag.

<script src="https://d3js.org/d3.v7.js"></script>

Introduction

Up until this section, we've been making use of several basic shapes as they are defined in the W3C specification. These include the rect, circle, and ellipse1. In this section, however, we'll look at how we can create custom and complex shape using the SVG path element2.

Let's use the creation of a zigzag as an example. Whilst you could say that it's possible to draw a zigzag using multiple rect elements at different positions and rotations (in the same way that you could draw any image with an unbounded number of rect elements behaving as pixels), it is certainly an infeasible and inefficient exercise.

This is where the SVG path element comes in. A path describes an outline of some shape that can be filled and/or stroked. Alternatively, a path could be left without a fill or stroke, so that it can be used to position text or define an animation path.

Paths are drawn as if a pen has been placed on paper at a current point, whereby following instructions move that pen in either lines or curves.

<svg>
  <path d="M20,60L60,20L100,60L140,20L180,60L220,20"
        stroke="black" fill="none"></path>
</svg>

We can see the output of the above SVG markup is a zigzag pattern. This shape has been specified using the d (data) property. In this case, we've used a series of moveto (M) and lineto (L) commands to construct our shape using coordinates.

We can see that the fill property has been explicitly set to "none". Otherwise, the default behaviour would be to fill the shape.

As we can see, this is not the desired output for our zigzag shape.

Let's see how we can create the same complex shape using D3.js.

A Container for the Output

This is where you will see the output of the code cells that follow it, provided they are referencing the corresponding id.

<div id="container"></div>

Creating an Empty SVG

We'll create a new detached <svg> element and use the returned selection throughout the rest of this section.

const svg = d3.create("svg");

Creating a Complex Shape with Paths

To create the same zigzag as above we need to complete three steps.

  1. Populate a data structure with our coordinates.
  2. Construct a line generator with d3.line()3.
  3. Generate a line by passing our populated data structure to the line generator.

Let's get started.

Populating a 2D Array

We'll use a simple 2D array for our data structure, passing in the coordinates that specify our zigzag shape. We'll store this in the data variable.

var data = [
    [20, 60],
    [60, 20],
    [100, 60],
    [140, 20],
    [180, 60],
    [220, 20]
];

Constructing the Line Generator

Next, we'll need to construct our line generator using d3.line(). We'll store this in the lineFun variable.

var lineFun = d3.line();

Generate the Path

Then we'll generate the zigzag line by passing our path data into our line generator, i.e. lineFun(data). This will be used to set the d (or data) property of our path element.

To create a <path> element with D3.js we can invoke the d3.append(name) function on our svg selection and pass in the name of the element. We'll also specify the stroke and fill properties.

var line = svg.append("path")
    .attr("d", lineFun(data))
    .attr("stroke", "black")
    .attr("fill", "none");

Appending to the Container

Finally, let's append everything to our container.

d3
    .select("#container")
    .append(() => svg.node());

We can see the output by checking on our container with the corresponding id, which in this case is where id=container.

Conclusion

If we inspect the HTML, we will see the <svg> and <path> elements have been added to the <div> where the id=container. We can also see that the <path> element's d attribute contains the path data that specifies our zigzag. We also have the stroke set to black, and the fill set to none.

<div id="container">
    <svg>
        <path d="M20,60L60,20L100,60L140,20L180,60L220,20"
        stroke="black" fill="none"></path>
    </svg>
</div>

  1. W3C. Basic Shapes, https://www.w3.org/TR/SVG/shapes.html. 

  2. W3C. Paths, https://www.w3.org/TR/SVG/paths.html. 

  3. M. Bostock. d3-shape: Lines https://github.com/d3/d3-shape#lines. 

Support this work

You can support this work by getting the e-books. This notebook will always be available for free in its online format.

Visualisation with D3.js v7

A practical book on visualisation with D3.js version 7 that shows you how to create visualisations from the ground up.

Get the book