One of the most common visualizations is a line chart. D3 is not a charting framework, but instead allows you to manipulate the document based on data. That’s what you’re actually doing with D3: adding elements to a document, removing them, updating them, etc. The advantage is that you are much more flexible in creating the visualization that you want. Some may consider it a slight disadvantage that you may do have to do some extra work to get things done.
For this tutorial we’re going to create a basic line chart with an x-axis and y-axis, tickmarks and labels.
First, we defined some variables:
var data = [3, 6, 2, 7, 5, 2, 1, 3, 8, 9, 2, 5, 7], w = 400, h = 200, margin = 20, y = d3.scale.linear().domain([0, d3.max(data)]).range([0 + margin, h - margin]), x = d3.scale.linear().domain([0, data.length]).range([0 + margin, w - margin])
The data variable contains our dataset we want to display as a line chart. The w and h variables are used for the width and height of our chart and the margin will be used to create some room to display our labels. The y and x variables are our linear scale functions, and remember that you can use x and y as functions. The scales are used to convert our data values (which are defined in the domain of the scale) to x- and y-positions on the screen (which are defined in the range of the scale). Note the use of margin in the range.
Next we append an svg element to our document with the proper width and height, and then we append a g element to this svg element so that all the elements that will be appended to this g element will be grouped together. The transformation that we apply on the g element makes sure that our coordinate grid moves down 200 pixels.
var vis = d3.select("body")
.append("svg:svg")
.attr("width", w)
.attr("height", h)
var g = vis.append("svg:g")
.attr("transform", "translate(0, 200)");
In order to create a line chart, we’re going to add an path element to our visualization. This path element needs a d attribute that contains the data for the path. Now, you could write that yourself, but that may be a little hard to do, so we use the helper function d3.svg.line to do that for us (see Tutorial: Line interpolations in D3 for more details on this helper function). Now we add the line variable which is, just like the scales earlier, a function that you can call. So when we bind our data to the path, this d3.svg.line function will be called so that the value of the d attribute will be created:
var line = d3.svg.line()
.x(function(d,i) { return x(i); })
.y(function(d) { return -1 * y(d); })
The i parameter is the index of the current item, and the d is the current item itself. Note the usage of the scale functions (x() and y() to convert from i and d to x- and y-coordinates (note the -1. This is needed because right now the coordinate have a positive y-axis down, and since we have translated our g down 200 pixels, we need to use the negative values of the y-axis now). To use our line function we add a path element to our g element like this:
g.append("svg:path").attr("d", line(data));
Next up is adding the x-axis and y-axis. The following snippet adds them by appending a line to our g element.
g.append("svg:line")
.attr("x1", x(0))
.attr("y1", -1 * y(0))
.attr("x2", x(w))
.attr("y2", -1 * y(0))
g.append("svg:line")
.attr("x1", x(0))
.attr("y1", -1 * y(0))
.attr("x2", x(0))
.attr("y2", -1 * y(d3.max(data)))
Next are the labels. We can use a convenient function of the scales here: x.ticks() and y.ticks(). These functions will return the proper tickmarks, and you can provide how many you want. D3 does return nicely rounded numbers though. Also note the .text(String) usage for obtaining the string value of the current data item. The labels are aligned in the center by using .attr("text-anchor", "middle"). And for the y-labels I’ve used dy in order to vertically position the labels correctly.
g.selectAll(".xLabel")
.data(x.ticks(5))
.enter().append("svg:text")
.attr("class", "xLabel")
.text(String)
.attr("x", function(d) { return x(d) })
.attr("y", 0)
.attr("text-anchor", "middle")
g.selectAll(".yLabel")
.data(y.ticks(4))
.enter().append("svg:text")
.attr("class", "yLabel")
.text(String)
.attr("x", 0)
.attr("y", function(d) { return -1 * y(d) })
.attr("text-anchor", "right")
.attr("dy", 4)
The last thing to do is to add the ticks themselves. These are actually just very short lines, so all you have to do is to provide the start x- and y position (x1 and y1) and the end x- and y-position (x2 and y2).
g.selectAll(".xTicks")
.data(x.ticks(5))
.enter().append("svg:line")
.attr("class", "xTicks")
.attr("x1", function(d) { return x(d); })
.attr("y1", -1 * y(0))
.attr("x2", function(d) { return x(d); })
.attr("y2", -1 * y(-0.3))
g.selectAll(".yTicks")
.data(y.ticks(4))
.enter().append("svg:line")
.attr("class", "yTicks")
.attr("y1", function(d) { return -1 * y(d); })
.attr("x1", x(-0.3))
.attr("y2", function(d) { return -1 * y(d); })
.attr("x2", x(0))
And that’s it. Finally, some of the styling of the objects was moved to a style section at the top of the page in order to get the final result:
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
line {
stroke: black;
}
text {
font-family: Arial;
font-size: 9pt;
}
View a live version here.



