In my last post, I gave a demonstration of drawing paths in D3. There are a few tricks to understand how to make good quality graphing with D3 that may not be completely intuitive.

Again, let’s start with our basic SVG canvas object.

<svg id="canvas" width="400" height="200" style="background-color:lightgray;"></svg>

Let’s grab our SVG object, and let’s capture the width and height values.

var svg = d3.select("#canvas");
var width = +svg.attr("width");
var height = +svg.attr("height");

Next, we’re going to manually add a path by mapping out its coordinates. We will set the fill to none, so that we only get a line.

var path = svg.append("path")
    .attr("fill", "none")
    .attr("stroke", "mediumblue")
    .attr("strokewidth", 4)
    .attr("d", "M0,100L100,50L200,175L300,75L400,150");

If we don’t explicitly add the fill: none attribute, this is what D3 will draw. You’ll notice that D3 connects the first and last points and colors in the gaps with the default pen.

Often, when producing a graphic, we want to color the area below the line, but not the area above the line. We can do this by adding two more data points. One point would be the bottom-left corner, and the other would be the bottom-right corner.

var path = svg.append("path")
    .attr("fill", "lightblue")
    .attr("stroke", "mediumblue")
    .attr("stroke-width", 4)
    .attr("d", "M0,100L100,50L200,175L300,75L400,150L400,200L0,200");

This looks pretty good, and our fill area is light blue as expected, but you’ll notice that we have some extra lines now, along the right and bottom borders.

The solution to this is to have two separate path objects. The first object will be the area; the second will be the line.

var area = svg.append("path")
    .attr("fill", "lightblue")
    .attr("stroke", "none")    
    .attr("d", "M0,100L100,50L200,175L300,75L400,150L400,200L0,200");

There, that’s much better looking. One more thing: we probably won’t ever directly edit the d attribute of a path. Instead, we will use D3’s datum() function. Usually, we will start with our line data. Remember, to create our area data, we just need to add two additional data points.

// Our line is the default generator.
var lineGenerator = d3.line();

// Create the line data as [x, y] pairs.
var lineData = [[0, 100], [100, 50], [200, 175], [300, 75], [400, 150]];

// Create a copy of the line data and add two data points.
var areaData = lineData.slice();
areaData.push([400, 200]);
areaData.push([0, 200]);

// Draw the area using the datum() function and the lineGenerator.
var area = svg.append("path")
    .attr("fill", "lightblue")
    .attr("stroke", "none")    
    .datum(areaData)
    .attr("d", lineGenerator);

// Draw the line using the datum() function and the lineGenerator.
var line = svg.append("path")
    .attr("fill", "none")
    .attr("stroke", "mediumblue")
    .attr("stroke-width", 4)
    .datum(lineData)
    .attr("d", lineGenerator);

And that’s it. Go forth and create those pretty graphics!