d3 and me

So I want to learn d3. I daresay it’s the Javascript standard for data visualization.

My d3 process goes like this: raw data -> d3 processing (grouping, reducing) -> d3 makes data points as SVGs  (rendering, animating)

A web-developer like me will try to apply habits and mental models from different* web technologies. I’ve encountered two big mental hurdles so far;

  1. API: d3 vs jQuery
  2. Elements/styling: SVG vs HTML

Below I describe the differences that I struggle with. Hopefully they help you learn d3!


*As a general note, different does not imply “better” or “worse”; these technologies can do a lot of the same stuff. But each stack excels in a different context, and context often explains their differences.

API

.append()

d3

returns the thing that was appended (i.e. child), so…

d3.select('body').append('table').append('tbody')

creates a DOM like…

  • body
    • table
      • tbody

jQuery

returns the thing that was appended-to (i.e. parent), so…

$('body').append('<table>').append('<tbody>')*

creates a DOM like…

  • body
    • table
    • tbody**
  • *Yes, can do $(‘body’).append($(‘<table>’).append(‘<tbody’>)). 
  • **Not a valid DOM. That’s why the d3 method seemed unintuitive; I wanted to nest append() methods like this.

Lesson-learned:

While d3 and jQuery both use chaining; (as in: object.method() returns the same object);

  • their methods don’t always chain; memorizing which methods are chaining methods is a learning curve in both languages
  • and they don’t chain consistently with one another (i.e. jQuery’s object.append() returns object, d3’s append() returns a newObject)

selecting vs subSelecting

Imagine the  DOM looks like the 2×2 table here; 2 rows (tr), 2 columns per row (td)

  • tbody
    • tr
      • td
      • td
    • tr
      • td
      • td

selecting

d3 uses selectAll() where jQuery uses $()*

Both methods accept a string with a CSS3 selector; like the native Javascript document.querySelectorAll(). In this case, they select the rows:

  • d3.selectAll(‘tbody tr’)
  • $(‘tbody tr’)

They both return flat Javascript array-like** objects pointing to the same DOM objects…

  • <tr>
  • <tr>

subSelecting

After selecting you have a variable pointing to rows. Imagine you must select the cells within those rows; I call it “subSelecting” for lack of a better word***

We start with the results of the select from above. jQuery uses a new method; find(), while d3 chains a selectAll, but they accept the same argument:

  • d3.selectAll(‘tbody tr’).selectAll(‘td’)
  • $(‘tbody tr’).find(‘td’)

And while they return Javascript pointing to the same DOM objects, they don’t return them in the same structure;

  • jQuery returns a flat Javascript array-like
    • <td>
    • <td>
    • <td>
    • <td>
  • d3 returns a nested Javascript object; they are implicitly nested, but I’ll show it explicitly:
    • <tr>
      • <td>
      • <td>
    • <tr>
      • <td>
      • <td>

More here

Lesson-learned:

  • d3 is more often applied when creating multi-dimensional HTML or SVG trees;
  • therefore d3 tends to produce and/or return results in a multi-dimensional structure (vs flattened)

As I said, it’s clear that the context explains their differences.

*I’m referring to the query overload of the jQuery() method, aka $();  $() can do many things. See below re: “flexible”

**I say “array-like” and later, “nested”… These are not Javascript arrays; they are custom Javascript objects and the d3 object is altogether different from the jQuery object. They have some uses in common with arrays, like iterating (forEach), or mapping (map). But I say “array-like” to illustrate their (implied) structure in the most abstract sense. I say “nested” because the d3 objects have properties and methods that imply a nested structure.

***Yes, subSelecting is a contrived example. We could select the ‘td’ directly without selecting ‘tr’ then subSelect its ‘td’. In fact, it’s worth noting a simple select without any subSelect produces the same (flat) result for both jQuery and d3, all of these produce the same result:

  • $(‘tbody tr td’)
  • d3.selectAll(‘tbody tr td’).
  • $(‘tbody td’)
  • d3.selectAll(‘tbody td’)

So here we draw another lesson:

These return equivalent (flat) results in jQuery****:

  • $(‘tbody tr’).find(‘td’)
  • $(‘tbody tr td’)

These do not return equivalent results in d3:

  • d3.selectAll(‘tbody tr’).selectAll(‘td’)
    • returns nested
  • d3.selectAll(‘tbody tr td’)
    • returns flat

****Yes, $(‘tbody tr td’) is faster than $(‘tbody tr’).find(‘td’), even though they produce the same result. That’s beside the point.

Creating

d3 helps us create HTML or SVG visualizations to represent data. But “create visualization to represent data” does not adequately describe the workflow or the API.  A better term is: d3 binds the visualization to the data. This example illustrates:

Wrong

d3.select(‘body’).data([1,2,3]).enter().append(‘p’)

returns Javascript array pointing to:

  • null
  • <p>
  • <p>

creates (probably invalid DOM, and not what I wanted!)

  • body
  • p
  • p

Right

d3.select(‘body’).selectAll(‘p’).data([1,2,3]).enter().append(‘p’)

returns a Javasript array-like…

  • <p>
  • <p>
  • <p>

creates

  • body
    • p
    • p
    • p

Lesson-learned

  1. d3 starts with a selection, using selectAll().
    1. It’s counter-intuitive because when you get started, the items (‘<p>’) probably won’t exist in the DOM
  2. Then bind to data using data().
    1. d3 will handle these 3 scenarios:
      1. there is more data than <p> elements (i.e. even if there are no <p> elements!)
      2. there are fewer data than <p> elements
      3. there is the same number of data and <p> elements
    2. binding is a better word than representing because d3 handles these scenarios exactly how you’d expect; this is the beauty of d3:
      1. Scenario 1 creates and binds <p> elements for the newly-introduced data with enter() method
        1. Hence I needed to selectAll(), and then enter()
      2. Scenario 2 removes excess <p> elements which are bound to missing data with exit() method

more here.

Styling, style() [d3] vs css() [jQuery]

d3

Uses .style()

  • d3.selectAll(‘p’).style(‘font-family’, ‘arial’)

jQuery

Uses .css()

  • $(‘p’).css(‘font-family’, ‘arial’)

Both methods chain; i.e. they return the object they were called on.

Both produce:

  • <p style=”font-family:arial;”></p>

Summary of Lessons Learned

jQuery and d3 have some overlap in functionanlity and API. But they are distinct:

  • jQuery is a powerful and flexible do-anything library
  • d3 excels for data visualization. In particular:
    • Expresses richness of data with dimensional/nested selectors and appendors
    • Binds data to its visualization; the bind pattern is: 1) select(‘visualization’).data(rawData) 2) enter() 3) exit()

While there are similarities in their API , don’t assume anything. In particular, like-named methods won’t always:

  • do the same thing
  • return the same thing
  • operate at the same speed

Moreover, sometimes differently-named methods sometimes:

  • do the same thing
  • return the same thing

Coming soon…

More on SVG vs HTML…

Questions for you to consider

What type of object is returned by select/selectAll? Looks like an Array; I can’t see the data method when inspecting it.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: