D3: Thinking with Joins

D3 is a popular HTML5 visualization framework. While similar to other JS frameworks in its exposure of CSS/SVG, its enter()/exit() abstraction is an elegant leap for structuring code. Check out Mike Bostock's short and direct explanation Thinking with Joins:

Say you’re making a basic scatterplot using D3, and you need to create some SVG circle elements to visualize your data. You may be surprised to discover that D3 has no primitive for creating multiple DOM elements. WAT?

I particularly appreciated the practicality of this model for designing animated transitions. You can also check out the beautiful gallery of examples.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

How is this an elegant leap for structuring code?

Most JavaScript frameworks do browser sniffing to decide how to gracefully degrade functionality, which often leads to incorrect degradation of behavior. Also, it is very hard to reason about the behavior of a most JavaScript programs built in these frameworks.

That said, can you justify how D3 is an improvement over decades-old technology, e.g. the Morphic approach to graphics? There are already two ports of Morphic to JavaScript:

Lively Kernel completely rejects the DOM and CSS, in exchange for a pure SVG rendered web browser. In essence, it shows what the Web could be like if a web browser did not have to know how to interpret its formats.

Morphic.js is a little less cavalier, as it uses the Canvas element and is thus still dependent / tightly coupled to HTML5 for behavior.

Most JavaScript frameworks

Most JavaScript frameworks do browser sniffing to decide how to gracefully degrade functionality

D3 is agnostic to the choice in primitives. For example, I use SVG and DOM together. For big data, we're actively researching a WebCL backend.

More importantly, this isn't the pain point D3 addresses.

Also, it is very hard to reason about the behavior of a most JavaScript programs built in these frameworks.

Reasoning about non-trivial visualizations, in most languages and frameworks, is terrible. D3 is a step up, especially over using low-level SVG, canvas, etc. APIs.

That said, can you justify how D3 is an improvement over decades-old technology, e.g. the Morphic approach to graphics? There are already two ports of Morphic to JavaScript

Designers use D3 en masse, and nobody uses morphic/lively, despite all of these having JS implementations made by experts and D3 being relatively new. Turning it around, why do morphic, lively kernel, etc. consistently fail?

More seriously, I like D3 for several reasons:

  • The creators are domain experts (for visualization) who dog food their work: again, check out their example gallery
  • Designing a good visualization is hard; most are tweaks on a small set of established patterns. Furthermore, most designers are not programmers nor mathematically inclined. D3 provides a large library of prepackaged layouts (e.g., force directed graphs).
  • D3 is structured for the common case of adding, removing, and updating different collections of data from a visualization. The page I linked shows how to easily add animated transitions to data surrounding these steps.
  • D3 is canonical MVC. Speaking to the above point, much of the control layer, which is typically the ugly part, is phrased in terms of relational operators.
  • D3 works well on the platform. This is an engineering point, but important in practice.

A lot of D3 would look very

A lot of D3 would look very familiar to us :). The enter/exit operators look similar to Superglue's list connection concept, where connecting to a list would together would create a bunch of objects to handle the connection (so, say a row for each email object in a JTable), but declarative and without the need for an exit.

The enter and exit is really

The enter and exit is really handy. For example, you want an animated entry or exit as an item moves between collections, such as morphing color, opacity, and size. This decouples creating an element from animating it: it may be created once, but entered/exited multiple times. I'm not sure I see how that would work in Superglue, maybe with a thin library on top?

The point about superglue

The point about superglue (compared to other FRP-like systems) was the ability to abstract over objects, so you could (a) write a rule that connected all signals of some tree-like type (e.g., to animate them in sync) or (b) make connections that caused objects/signals to be created elastically. D3 supports these features; albeit very differently, more imperative/functional (selectAll and enter/exit), which should be more expressive than superglue's declarative constructs.

D3's enter/exit look like good abstractions to add to Bling. In Bling, you can animate a value fairly easy (w.Height.Animate.To = 100d), but there is no notion of abstracting over value collections like there was in superglue.

Fair question

Turning it around, why do morphic, lively kernel, etc. consistently fail?

This probably depends on your definition of failure.

For Lively Kernel, it is still very much beta software. For Morphic in general, I don't think it has ever truly failed. My perspective might sound like denial, but consider it this way: If it has failed, then everything else has also failed, too.

Also, I was questioning what frameworks you had in mind besides the ones I listed. I was assuming you were referring to jQuery, Dojo, YUI, Ext.js/Sencha, etc. (Do you include Flapjax as a non-leap?) But I still wanted to hear your thoughts on those. Perhaps private discussion is best.

More seriously, I like D3 for several reasons:

I don't see it. One of the most inspiring videos on graphics programming I have ever watched was Alan Kay giving a brief history of user interface design and programming. His point boiled down to this: If the language you use to define the user interface disallows immediate feedback, then you have already lost. Why is that so conceptually significant? Think of the approaches we have seen here on LtU in the past:

  • Concrete Syntax - Martin Bravenboer's example, where he creates an XML syntactic abstraction over Java Swing, so that users can express layout by containment
  • Declarative layout and/or UI languages?

For the first approach, it is obviously wrong - it is a heuristic with the assumption that layout math is always hierarchical and therefore containment is the only sensible abstraction. But what do you do for scenarios like parallax scrolling games, just as an example. There is no containment pattern. Anything that involves more than 2 dimensions also cannot use a containment pattern, so containment cannot express 3D user interface concepts like perspective and focus. The only thing the first approach does well - and it is all they are really claiming to achieve - is that for layout rules that can be expressed by containment, the code is more readable and shorter than code that isn't. But I think that claim itself deserves more scrutiny. If we wanted brevity, we could write in a stack-based language or point-free style.

For the others, the major bug in their designs is obvious from the critique of concrete syntax to express containment. None of these alternatives capture the actual art of the user interface.

More importantly, this isn't the pain point D3 addresses.

I agree -- D3 seems superior to Processing for visualizations. But you were talking about how hard it is to reason about the behavior of most JavaScript programs built in JavaScript frameworks.

•D3 is canonical MVC

I did not understand how. Canonical MVC to me is the example Alan Kay gave of how they built the Agent spreadsheet program in Smalltalk for the CIA:

The strongest test of any system is not how well its features conform to anticipated needs but how well it performs when one wants to do something the designer did not foresee. It is a question less of possibility than of perspicuity: Can the user see what is to be done and simply go do it?

Suppose one wants to display data as a set of vertical bars whose height is normalized to that of the largest value, and suppose such a bar-chart feature was not programmed into the system. It calls for a messy program even in a high-level programming language: in a spreadsheet it is easy. Cells serve as the "pixels" (picture elements) of the display: a stack of cells constitutes a bar. In a bar displaying one-third of the maximum value, cells in the lowest third of the stack are black and cells in the upper two-thirds are white. Each cell has to decide whether it should be black or white according to its position in the bar: "I'll show black if where I am in the bar is les than the data I am trying to display: otherwise I'll show white."

This example is canonical MVC, because every cell in the spreadsheet has its own MVC pattern, as Alan's example describes. More importantly, each cell contributes to the overall look and feel, without knowing how. It's pretty easy to unit test.

Alan goes on to describe the browser conceived by Larry Tesler, and how it can be described in just three rules.

I hope this example illustrates better what I am expecting from leaps of elegance, without coming across as pedantic.

Also, I was questioning what

Also, I was questioning what frameworks you had in mind besides the ones I listed.

I've seen too many frameworks to point any ones out ;-)

Note that I'm not claiming D3 is any sort of platonic ideal. However, for a programmatic visualization framework, I'm impressed with the simple core idea.

If the language you use to define the user interface disallows immediate feedback, then you have already lost.

That style of reasoning is strange: "if pet feature X is not present, the system is a failure." D3 is a proven success in that designers are able to use it. For the concrete feature of direct manipulation, as you are well aware, the idea has been repeatedly reinvented for many systems, and I can easily see extending D3 with it.

I agree -- D3 seems superior to Processing for visualizations. But you were talking about how hard it is to reason about the behavior of most JavaScript programs built in JavaScript frameworks.

No, I'm talking about non-trivial visualization systems in general. As a subtle point, I meant visualizations (charts, graphs, etc.) rather than something like a HUD.

This example is canonical MVC

This example illustrates something else to me, but I'll leave you to ponder that ;-)

I hope this example illustrates better what I am expecting from leaps of elegance, without coming across as pedantic.

I think I see where I am not coming through. I am not looking for elegant intellectual thrills ("everything is an object! MVC-ception!"). I *don't* want to optimize for Alan Kay's test. Instead, I want to make the typical case dead simple.

As in my comment to Sean, it may be possible to do it as simple tweaks on other systems. That's great -- we can get extra benefits this way. However, D3 illustrates the use case that they must support. In lieu of some sort of fantastic breakthrough, it shows a simple way to do it.

Perhaps to add context to this, I stumbled into D3 because I am following the exact use case: an interactive data visualization where users slice and dice entries. In two days, I had a faster, more animated, and cleaner implementation than I did with a few days in another system -- and this included the time to learn it. I've written enough AS, FRP, etc. to appreciate this :)

I think I see where I am not

I think I see where I am not coming through.

Basically. Thanks.