In this tutorial we’re going to explore line interpolations in D3.
First we start with 2 scales that we will use to convert values to x- and y-coordinates on the screen:
var x = d3.scale.linear().domain([0,10]).range([0,400]), y = d3.scale.linear().domain([0,1]).range([0,50]), groupHeight = 60, topMargin = 100
Next we generate some random data:
var data = []
d3.range(10).forEach(function(d) { data.push(Math.random()) })
We’re also creating an array which contains all the possible interpolations D3 supports. We’ll see the effects of every interpolation in a moment:
var interpolations = [ "linear", "step-before", "step-after", "basis", "basis-closed", "cardinal", "cardinal-closed"]
In SVG there is a difference between a line and a path. A line is a straight line where you define the start and end position of the line: , whereas with a path you draw the outline of any arbitrary shape by specifying a series of connected lines, arcs, and curves. You do this by specifying the d attribute of the path. Every path must begin with a moveto command. The command letter is a capital M followed by an x- and y-coordinate, separated by commas or whitespace. This command sets the current location of the “pen” that’s drawing the outline. This is followed by one or more lineto commands, denoted by a capital L, also followed by x- and y-coordinates, and separated by commas or whitespace. You can see more of this specification here.
In our example we’re not actually creating an SVG line, but an SVG path, so we need to set the d attribute of the paht. Luckily D3 has a helper function to ease the burden to create this data: d3.svg.line. For this helper function you can set:
- an accessor function for obtaining x values
- an accessor function for obtaining y values
- an interpolation type, which defaults to
linear - a tension value which affects the
cardinalinterpolations only
In our example, we want to show the different kinds of interpolations for the same data, so we create a function that takes the name of an interpolation as an argument, and then returns the d3.svg.line function as a result. This is the code that does that (you can play with the out-commented tension property to see the effect):
function getLine(interpolation) {
return d3.svg.line().x(function(d,i) {
return x(i)
}).y(function(d) {
return y(d)
}).interpolate(interpolation)
//.tension(0)
}
Note the following: the function for x has 2 arguments: d and i. The d is the current item in the dataset (which we will provide later), and i is the index of the current item in the dataset. Also note that we’re using the x-scale to convert i to an x-coordinate, and the y-scale to convert the data value to a y-coordinate.
Now we initialize the visualization:
var vis = d3.select("body")
.append("svg:svg")
.attr("class", "vis")
.attr("width", window.width)
.attr("height", window.height)
Next up is greating a group for each of the lines we want to show:
var lg = vis.selectAll(".lineGroup")
.data(interpolations)
.enter().append("svg:g")
.attr("class", "lineGroup")
.attr("transform", function(d,i) {
return "translate(100," + (topMargin + i * groupHeight) + ")"
}).each(drawLine)
We set the interpolations array as data for this group, so that svg:g elements for each of the interpolations will be added to the visualization. The svg:g element can be used to group other elements together, so that if you apply a transformation to the group for instance, it will be applied to all of its members. Note that we add the class lineGroup in our selection to select all these elements. Next we set the transform attribute, and we use the index to position the groups based on their position in the interpolation array. For each of the group, we want to draw a line. We do that by calling the drawLine function in the .each(drawLine) statement. The drawLine function itself looks like this:
function drawLine(p,j) {
d3.select(this)
.selectAll(".lineGroup")
.data(data)
.enter().append("svg:path")
.attr("d", getLine(p)(data))
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 3)
//.attr("stroke-dasharray", "15 5")
}
The drawLine function itself has to parameters: p and j where p is the parent data item (the current interpolation name), and j is the parent index. First we select the current element with d3.select(this), and next we select all the .lineGroup elements. We assign the line data to the data property, and append a path to each lineGroup element. The d attribute calls the getLine function and provides the current interpolation name as an argument. The result of that is the d3.svg.line function with the that uses the interpolation we just provided. Next we assign the line data to this function so that D3 will calculate the data string that will be used by the d attribute of the svg:path element. Finally we set some basic properties. The final out-commented is one of the stroke properties you can set, where 15 is the dash length and 5 is the gap length. Just play around with those properties to see what else is possible.
This concludes this tutorial. All the lines you see are using the same data, but they use different interpolations.




