ee2Dev
ee2Dev

Reputation: 1998

d3.js data join shows strange result

I am using d3v4 and within the html document I have 20 g.node elements, with 4 having the value: d.nameY === "responded No".

The following statement works correct:

d3.select("g.sankeyFrame.single")
            .selectAll("g.node")
            .filter( function(d) { return d.nameY === "responded No";})
            .size(); 

It returns 4 as desired.

However, the following data join doesn't return the expected selection:

d3.select("g.sankeyFrame.single")
            .selectAll("g.node")
            .data(["responded No"], function(d){ return d.nameY;})
            .size();

It returns 0, it should return all 4 g.node elements, where d.nameY === 4.

What possible reason prevents the data join from working? (The code base is too large to publish here)

Upvotes: 1

Views: 276

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102194

What possible reason prevents the data join from working?

No reason at all. It is working. And the result is not wrong, that's the expected behaviour. You have another problem here.

To show you the problem, let's create a very simple demo, which appends 20 <div>s, 4 of them with the datum "foo". Here is the code using your first approach, with filter:

var p = d3.select("body")
  .selectAll(null)
  .data(d3.range(20).map(function(d) {
    return d < 4 ? "foo" : "bar"
  }))
  .enter()
  .append("div")
  .html(String);

var filtering = d3.selectAll("div")
  .filter(function(d) {
    return d === "foo"
  }).size();

console.log("size is: " + filtering)
<script src="https://d3js.org/d3.v4.min.js"></script>

Now let's see your second approach:

d3.select("g.sankeyFrame.single")
        .selectAll("g.node")
        .data(["responded No"], function(d){ return d.nameY;})
        .size();

You have two problems here:

  1. The key function will not work. There is no property nameY in a simple, flat array like ["responded No"]. That's why your selection's size is 0.
  2. There is just one element in that array. So, even if you remove the wrong key function, that selection will have just one element. Let's prove it:

var p = d3.select("body")
  .selectAll(null)
  .data(d3.range(20).map(function(d) {
    return d < 4 ? "foo" : "bar"
  }))
  .enter()
  .append("div")
  .html(String);

var dataBinding = d3.selectAll("div")
  .data(["baz"])
  .size();

console.log("size is: " + dataBinding)
<script src="https://d3js.org/d3.v4.min.js"></script>

That point #2 is the most important here: the size of the update selection returned by data() is the size of its array.

Finally, to clearly show that the data() is working, let's see the datum of each <div>:

var p = d3.select("body")
  .selectAll(null)
  .data(d3.range(20).map(function(d) {
    return d < 4 ? "foo" : "bar"
  }))
  .enter()
  .append("div")
  .html(String);

var dataBinding = d3.selectAll("div")
  .data(["baz"])
  .size();

d3.selectAll("div").each(function(d, i) {
  console.log("div number " + i + " - datum: " + d)
})
<script src="https://d3js.org/d3.v4.min.js"></script>

Upvotes: 2

Related Questions