a fun, difficult introduction to d3

Tom MacWright / @tmcw / tmcw
dev @MapBox
writing/hackin @macwright.org

want more words? here's an accompaniment

macwright.org/ presentations/dcjq/

(pretty things)

minute (keystrokes)



what is d3?

what is d3 not?

Not a chart library (though you can make charts with it)

Not a map library (though you can make maps with it)

what is d3 not?

Not a compatibility layer (it doesn't work with bad browsers)

Not about SVG or HTML or Canvas (though you can use it with them)

what is d3 not?

not an SVG abstraction layer

it doesn't have its own way of making a line or a circle. it makes you deal with svg elements as svg elements. plus, you can deal with HTML elements and Canvas elements!

d3 is data→documents

d3 is a general purpose visualization library

d3 is a general purpose visualization library

d3 is a general purpose visualization library

what is general purpose about visualizations?

the transformation of data into information

the transformation of data into documents

the transformation of data into elements

pretty things break

challenge 1, challenge 2

overlap of d3 and jQuery (there's a bit)

  .style('background', '#000')
  .on('click', function() {})

  .css('background', '#000')
  .click(function() {})
  function(err, data) { });

  function(data) { });

that's just the silly stuff, though

// a fully-featured jquery replacement
function $(x) {
  return document.querySelectorAll(x);
// a fully-featured jquery replacement
$.ajax = function(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.onload = callback;

let's get to the hard stuff, then

d3 requires deep proficiency in javascript

Javascript Primer

Let's review some Javascript (1x)

what is the difference between == and ===?


why did we learn that? because identifying objects is one of the biggest parts of the join

now let's understand the hardest part of d3 by building it from scratch.

the join

the final dish


you have the knowledge! time to d3.

  .data([1, 2, 3])

// an empty selection.
// looking for instantiations of data

// data, which would be bound to a
// selection
.data([1, 2, 3])

// for every time that we see data
// but we do not see an element

// append an element

// and fill it with text

// and fill it with text
// wait what

// what's going on here?

  .data([1, 2, 3])

// d3 has a few different
// functions that set stuff

// each takes a function
.attr('foo', function() { })

// and that function gets data
// from your .data()
.attr('foo', function(d) {
  return d.foo;

// like jQuery, you can chain these
  .attr('foo', 'bar')
  .attr('boo', 'burr');

// like jQuery, you can use them
// to get an existing value
var fooValue = blah.attr('foo');

// if you provide a static argument,
// it becomes a functor
.attr('foo', 5)

what's a functor? what a closure? time for javascript

// here's what a functor is
function functor(x) {
  return function() {
    return x;

we just used a closure.
don't know what a closure is?

// and what it does
var val = functor(10);

// val is now a function that
// always returns 10
assert.equal(val(), 10);

but what did you mean by .enter()?

d3 is all about enter, exit, and update

// this is an empty selection
var selection = d3.selectAll('div')
  .data([1, 2, 3]);
// for each part of the data which
// is not joined to an element in
// the selection,
// add an element
// for each part of the selection
// that is no longer in the data,
// remove it
// for each part of the selection,
// update some attribute
  .text(function(d) {
    return d.bar;

so data is bound to the DOM

but what does that mean?


<div class='joined-elem'></div>
// a joined element like this has
// a __data__ property where

we just awkwardly explained joins

read mike's explanations: bost.ocks.org/mike/join/ mbostock.github.com/d3/tutorial/circle.html

Let's make three little circles!


pretty things break


Why must everything be so hard!?

  1. Changing the DOM is mad expensive
  1. Changing the DOM is usually the most expensive part of your code unless you're a horrible Javascript coder
  1. Changing the DOM is mad expensive
  2. This makes animated transitions way slicker
  3. Post-eureka moment, it makes code way more compact
  4. Data updates, like real-time data or history viewers, become obvious rather than awful

Joining data to elements is the trickiest part of d3. Here are some less-tricky transformations

The Scale

    // data comes in
    .domain([0, 100])
    // representation comes out
    .range([0, 1]);

Geo Stuff

var projection = d3.geo.mercator();
// data goes in
// representation comes out
var px projection([lon, lat]);

Let's make Unknown Pleasures!


The Finished Dish

the code

pretty things break

force directed voronoi

chord diagram

how to write 'good' d3

Reuse your selections

Same rule as jQuery's reusing $blah = $('#blah')

var fooSelection = d3.selectAll('#foo');
// do not turn around and do
// again

Write reusable components (if any)


back to d3

d3 is filled with algorithms

voronoi, quadtrees, convex hull, projections, circle fitting


data → representation requires thinking

(for visualization)

d3 also has old school visualization whizzes

and they love math

want an abstraction?

var graph = new Rickshaw.Graph({
element: document.querySelector("#rick"),
renderer: 'bar',
  data:[{ x:0, y:40 }, { x:1, y:49 }],
}, {
  data:[{ x:0, y:20 }, { x:1, y:24 }],

4: Postscript, Where to Go From Here

Buy The Grammar of Graphics

It is not about d3.

d3 is about it.

See Mike's bits of code

It's zany.

Tools for writing d3

People who write about this

Thank you!

(ask me about MapBox and/or your inability to have a digital copy of DC's code of law)