Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing unwanted data inheritance with selection.select

Tags:

d3.js

In d3, selection.select has the side-effect of inheriting data from the parent nodes in the original selection. This is desirable in situations where data is shared between parent and child nodes so that updated data bound to the parent will get pushed to the child without requiring a data join at every level.

But what about situations where there is explicitly no relationship between the data bound to the parent and the data bound to the child? In this situation, selection.select can be insidious because simply by selecting a node you cause that node's data to be clobbered with unrelated parent data.

What is the best technique for avoiding this? I can think of a couple of options but neither seem wonderful:

  1. Always use selection.selectAll everywhere except for cases where implicit data inheritance is wanted. This is not ideal, however, because it makes usage of selection.select inconsistent with d3.select which is simply used to select an individual node (exactly what I want to do with selection.select).

  2. Use d3.select with a descendents selector instead of selection.select to isolate a specific node. The convenient thing about using selection.select is that it implicitly restricts the selection to descendents of the starting selection. Achieving this with the selector is not nearly as nice.

Personally, I'm not a huge fan of having a DOM-state-modifying side-effect in one particular form of some of the most commonly used functions in the API. I think I would find it easier to understand if there was an explicit call such as selection.update(selector) to be symmetrical with selection.append and selection.insert.

But in the current API, I'm wondering if there some other mechanism that can be used to effectively break inheritance when using selection.select?

like image 764
Scott Cameron Avatar asked Jul 24 '13 23:07

Scott Cameron


1 Answers

I did end up submitting an issue on the D3 Github: https://github.com/mbostock/d3/issues/1443. There isn't any resolution but there is a (I think) interesting discussion of the problem. At the very bottom, Mike does offer a work-around that would work, which I'll paste here for convenience:

Not a great answer, but one way you can prevent data inheritance is to have an intermediate node without bound data.

var intermediary = selection.append("div")
    .datum(function() { return null; });

Then, any select from the intermediary wouldn’t propagate data from the parent selection. But of course, the intermediate node in the DOM is somewhat unfortunate.

like image 53
Scott Cameron Avatar answered Nov 15 '22 02:11

Scott Cameron