I am learning D3, and how to nest or append elements to the page using D3’s data binding mechanism.
I have modified code found on http://www.recursion.org/d3-for-mere-mortals/ . I understand how to set up the svg canvas and I also understand the loops binding data to the rect, text and line elements.
What I don’t understand are the calls to selectAll('Anything1/2/3/4') below. They are clearly necessary, but what exactly am I selecting, and how do they fit in the data binding mechanism? Thank you.
<html>
<head>
<title>D3 Test</title>
<script type="text/javascript" src="d3/d3.v2.js"></script>
</head>
<body>
<script type="text/javascript">
var dat = [ { title:"A", subtitle:"a", year: 2006, books: 54, avg:10 },
{ title:"B", subtitle:"b", year: 2007, books: 43, avg:10 },
{ title:"C", subtitle:"c", year: 2008, books: 41, avg:10 },
{ title:"D", subtitle:"d", year: 2009, books: 44, avg:10 },
{ title:"E", subtitle:"e", year: 2010, books: 35, avg:10 } ];
var width = 560,
height = 500,
margin = 20,
innerBarWidth = 20,
outerBarWidth = 40;
var x = d3.scale.linear().domain([0, dat.length]).range([0, width]);
var y = d3.scale.linear()
.range([0, height - 2 * margin])
.domain([ 0 , 100 ]);
var z = d3.scale.category10();
var n = d3.format(",d"),
p = d3.format("%");
var canvas = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + 2 * margin + "," + margin + ")");
// outerbars
var outerBars = d3.select("svg")
.selectAll("Anything1").data(dat).enter().append("rect")
.attr("x", function(datum, index) { return x(index); })
.attr("y", function(datum) { return height - y(datum.books); })
.attr("height", function(datum) { return y(datum.books); })
.attr("width", outerBarWidth)
.attr("fill", "blue")
// innerbars
var innterBars = d3.select("svg")
.selectAll("Anything2").data(dat).enter().append("rect")
.attr("x", function(datum, index) { return x(index)+innerBarWidth/2; })
.attr("y", function(datum) { return height - y(datum.books)/2; })
.attr("height", function(datum) { return y(datum.books); })
.attr("width", innerBarWidth)
.attr("fill", "red");
// avg references
var barlabels = d3.select("svg")
.selectAll("Anything3").data(dat).enter().append("line")
.attr("x1", function(datum, index) { return x(index); })
.attr("x2", function(datum, index) { return x(index)+outerBarWidth; })
.attr("y1", function(datum) { return height - y(datum.books)/2; })
.attr("y2", function(datum) { return height - y(datum.books)/2; })
.style("stroke", "#ccc");
// titles
var barlabels = d3.select("svg")
.selectAll("Anything4").data(dat).enter().append("text")
.attr("x", function(datum, index) { return x(index)+innerBarWidth/2; })
.attr("y", height )
.attr("text-anchor", "end")
.text(function (d) {return d.title} );
</script>
</body>
</html>
Perhaps the most important, yet most difficult concept to understand in d3 is the selection (I highly recommend you bookmark and familiarize yourself with the API). On the surface, selections provide similar functionality to many other JavaScript libraries, such as jQuery:
jQuery:
d3:
Both these lines create “selection objects”, which are essentially DOM elements which have been grouped into a single object which gives you better control over the elements. Like other libraries, you can manipulate these “selected” elements in d3 using functions that are provided in the library.
jQuery:
d3:
Again, on the surface this is fairly easy to understand. What makes d3 so powerful is that it lets you take this a step further by allowing you to bind arbitrary data to the selected elements.
Let’s say you have a blank document and you want to add a couple paragraphs of text – and you have each paragraph of text stored in individual elements in an array:
Since we haven’t yet created these paragraphs, the following call will return an empty selection:
Note that
paragraphsis still a selection, it is just empty. This is a fundamental point in d3. You can bind data to an empty selection, and then use the data to add new elements using the entering selection. Let’s start over from our previous example and walk through this process. First, create your empty selection and bind thetextarray to it:Then, using the entering selection, append the
<p>elements to the body:Your DOM will now have:
There’s a lot that could definitely confuse you at this point, but I think this should give you a good start.
See also: Thinking with Joins.