selection.data returning different types of objects

Every loop, I perform some updates on a certain selection of objects (see code snippet below), starting with removing deleted elements using an exit() call. I just added a slider to modify a parameter in one of the objects, and when the slider moves I call the same update method (again with the code below). When the slider triggers the update, however, the selection is different... and in particular, the exit() method fails --- TypeError: selection.exit is not a function (and I think I'm avoiding the standard cause of that problem).

var selection = svgSim.selectAll(".bh")
    .data(binary);

// Remove old
console.log("sel = ", selection);
var olds = selection.exit();
olds.remove();

When I log the selection to console, the contents is basically the same... but there seems to be something different about the object type, or something like that. See the screen shot below. The first printout of selection ("sel = [...]") is when it works fine. The next time it raises the error, and the formatting of the print is different - although it seems to contain the same basic data.

  • Why is selection.data() returning different types of objects when called in different contexts?

  • What is the difference in the console.log output: what is pt (in the output) and what are the different types of objects being printed here.

Note: I understand if this non-MWE is insufficient to solve the problem entirely, which is why I've tried to ask a few specific (sub)questions which may help me find the problem, none-the-less.


The data looks something like,

var phaseInit = Math.random();
var binary = [
    {name: "a", phase: phaseInit, mass: m1},
    {name: "b", phase: phaseInit + 0.5, mass: m2}
];

And when the slider moves, I'm modifying the data like:

binary[0].mass = sliderScaleM1.invert(sval);

(very new to javascipt and d3)

enter image description here

1 answer

  • answered 2017-12-06 02:02 Gerardo Furtado

    Since we don't have access to a MWE (see this comment), this is a general answer trying to clarify the issue based on the information provided.

    In D3, the data() method accepts three things:

    1. An array;
    2. A function;
    3. Nothing.

    In the first and second cases, data() is a setter. However, in the third case, data() is a getter.

    We can see this in a basic example:

    var body = d3.select("body");
    var data = ["foo", "bar", "baz"];
    var sel = body.selectAll(null)
      .data(data);
    sel.enter()
      .append("p")
      .html(String)
    
    console.log(sel)
    <script src="https://d3js.org/d3.v4.min.js"></script>

    However, if we use data() as a getter, we don't have a selection anymore:

    var body = d3.select("body");
    var data = ["foo", "bar", "baz"];
    var sel = body.selectAll(null)
      .data(data);
    sel.enter()
      .append("p")
      .html(String)
    var sel2 = body.selectAll("p").data()
    
    console.log(sel2)
    <script src="https://d3js.org/d3.v4.min.js"></script>

    Because of that, you cannot call exit() on that variable: it is not a D3 selection, but just the data array.

    Looking at your console we can see that, at 19:57:07, sel is a regular D3 selection. However, at 19:57:12, sel is just an array, more specifically your data array.

    So, in conclusion, somehow in your code you're using data() as a getter, and the variable sel doesn't hold a D3 selection anymore.