Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

d3js: make new parent data descend into child nodes

Tags:

I can't work out how best to pass changes to the data which occur at a parent node (e.g. an SVG g element) down to it's children (e.g. SVG circle elements).

I've read this and this but still can't figure it out.

Here's a minimum working example. The example assumes you've got an object called svg which refers to a d3 selection containing an SVG element.

data = [{"id":"A","name":"jim"},{"id":"B","name":"dave"},{"id":"C","name":"pete"}];  g = svg.selectAll("g").data(data, function(d) { return d.id; }).enter().append("g");  g.append("circle")       .attr("r", 3)       .attr("cx", 100)       .attr("cy", function(d,i) {return 100 + (i * 30);})  // The data gets passed down to the circles (I think): console.log("circle data:"); d3.selectAll("g circle").each(function(d) { console.log(d.name); });       // Now change the data, and update the groups' data accordingly data = [{"id":"A","name":"carol"},{"id":"B","name":"diane"},{"id":"C","name":"susan"}]; svg.selectAll("g").data(data, function(d) { return d.id;});  // These are the results of the change: console.log("after change, the group has:"); d3.selectAll("g").each(function(d) { console.log(d.name); });      console.log("but the circles still have:"); d3.selectAll("g circle").each(function(d) { console.log(d.name); });    

Can anyone help me find a concise way to get the new names into all the child elements of a group? In my real-life example, each g contains many circles.

like image 264
LondonRob Avatar asked Sep 16 '13 15:09

LondonRob


2 Answers

There are 2 ways to propagate the data from parents to children:

  1. selection.select will do this implicitly. (The implementations of selection.append and selection.insert are actually based on selection.select internally)

    svg.selectAll("g").select("circle") 
  2. You can explicitly redo the data join using a function to receive the parent data and return it in an array for the child.

    svg.selectAll("g").selectAll("circle")     .data(function(d) { return [d]; }); 

These amount to the same thing. The first option relies on some special behaviour in select so it can be a bit surprising at first, but it is nice in that it makes the pattern for node update symmetrical with the pattern for node creation via insert/append. The second option is useful if you need to apply any changes to the data as it is being propagated.

Here's another article you didn't link to that might be useful also: Thinking with Joins

like image 117
Scott Cameron Avatar answered Oct 04 '22 02:10

Scott Cameron


Not sure if you figured it out, but this is definitely not in the documentation. All of the documentation that deals with element grouping does not seem to deal with the child selection and data inheritance to children.

The answer is to use the .each construct to update the children elements and append the children to the group enter() call.

data = [{"id":"A","name":"jim"},{"id":"B","name":"dave"},{"id":"C","name":"pete"}];  function draw(data) {   var g = svg.selectAll("g").data(data, function(d) { return d.id; })    genter = g.enter().append("g");    // This is the update of the circle elements -    // note that it is attached to the g data, not the enter()   // This will update any circle elements that already exist   g.each(function(d, i) {     var group = d3.select(this);     group.select("circle")     .transition()        .attr("r", 3)       .attr("cx", 100)       .attr("cy", function(d,i) {return 100 + (i * 30);})   }    // The data DOES get passed down to the circles, and the enter() statement   // will create a circle child for each data entry   genter.append("circle")       .attr("r", 3)       .attr("cx", 100)       .attr("cy", function(d,i) {return 100 + (i * 30);}) }  // Original drawing draw(data);  // Now change the data, and update the groups' data accordingly data = [{"id":"A","name":"carol"},{"id":"B","name":"diane"},{"id":"C","name":"susan"}];  // Second drawing, the SVG will be updated draw(data); 

Let me know if this works.

[This answer is based on some code grouping from this coderwall post: https://coderwall.com/p/xszhkg ]

like image 21
tmarthal Avatar answered Oct 04 '22 03:10

tmarthal