d3 (aka Data-Driven Documents) is a great little JavaScript framework for data visualization. It’s got a nice declarative syntax for DOM manipulation that’s quite readable, but takes a bit of effort to understand exactly what it’s doing.

Favorite links:

  • UPDATE: Dashing D3.js is an amazing series of tutorials with great conceptual grounding
  • d3 tutorials provide a great conceptual foundation
  • Thinking with Joins by d3 creator, Mike Bostick, helps explain the syntax for chaining methods
  • Scott Murray’s d3 tutorial offers a very nice step-by-step, covering a lot of the same ground as my little tutorial below with excellent discussions of the fundamentals.

I like to understand stuff by playing with it interactively, so I created a skeleton index.html which just includes d3.js and a style a div where I’ll display some data.

UPDATE: blank file below posted here

<html>
  <head>
    <title>d3 experiment</title>
    <script type="text/javascript"
            src="https://raw.github.com/mbostock/d3/master/d3.js">
    </script>
    <style type="text/css">
      .box {
        background-color: skyblue;
        width: 24px;
        height: 18px;
        padding: 4px;
        margin: 1px;
      }
    </style>
  </head>
  <body>
  </body>
</html>



Then in the FireBug console, we can interact with d3, the top-level object that allows us to access all of d3’s goodness.

>>> d3
Object { version="3.0.1", random={...}, ns={...}, more...}
>>>  body = d3.select("body")
[[body]]

Like jQuery, d3 let’s us “select” one or more DOM elements to operate on them. I only have one body tag, so I just get one element in an array — not yet sure why it needs a nested array. Now I can manipulate the DOM:

>>>  body.append('p').text('Hello d3!')
[[p]]

and “Hello d3!” appears at the top of my page. Yay! Of course that could have been written in a single line like:

d3.select("body").append('p').text('Hello d3!')

and if I want to change the text, I can use a regular old css selector to grab the paragraph element I just created:

d3.select("body p").text("Welcome to d3")

or, using the reference to the ‘body’ variable I created above:

body.select("p").text("d3 is cool")

Data-driven Boxes

Ok, now that we understand the basics, let’s put some boxes on the page:

body.append('div').attr('class','box')

and let’s add a couple with text in them:

 
body.append('div').attr('class','box').text('hi')
body.append('div').attr('class','box').text('foo')

With my set of boxes, I can select one or all of them:

>>> d3.select('.box')
[[div.box]]
>>> d3.selectAll('.box')
[[div.box, div.box, div.box]]

Then I can specify data to bind to each box and display it. I’ve read that d3 can deal with all sorts of data (like json, csv, etc.) but we’ll start with an array of numbers.

>>> my_data = [20, 7, 32]
[20, 7, 32]
>>> d3.selectAll('.box').data(my_data).text( function(d) { return d } )
[[div.box, div.box, div.box]]


We can see that our data is associated with the DOM element and we can get at it via JavaScript in the console. (Of course, we should only do that for debugging. I would guess that __data__ is the private implementation of d3’s data binding.)

>>> d3.select('.box')[0][0].__data__
20

We can change the data like this:

>>> new_data = [10, 50, 25]
[10, 50, 25]
>>> d3.selectAll('.box').data(new_data)

You’ll see that the page doesn’t change visually, but in the console, you can see that the data does:

We need to explicitly tell d3 to do something with the data like this:

d3.selectAll('.box').text( function(d) { return d } )

We can also use this handy shortcut:

d3.selectAll('.box').text( String )

9 thoughts on “d3.js experiments in the console

  1. Just wanted to say I appreciate your tutorial. Hopefully somebody writes a d3 book soon.

  2. About your question regarding nested arrays as result of selections, there is a note on https://github.com/mbostock/d3/wiki/Selections :

    Operating on Selections

    Selections are arrays of elements—literally. D3 binds additional methods to the array so that you can apply operators to the selected elements, such as setting an attribute on all the selected elements. One nuance is that selections are grouped: rather than a one-dimensional array, each selection is an array of arrays of elements. This preserves the hierarchical structure of subselections. Most of the time, you can ignore this detail, but that’s why a single-element selection looks like [[node]] rather than [node]. For more on nested selections, see Nested Selections.

  3. Finally! A way to get into the guts of d3 and play without constantly refreshing a page and the browser. Thanks!

What do you think?