Trouble updating child elements in a group element

668 views
Skip to first unread message

kank

unread,
Nov 24, 2012, 1:41:24 PM11/24/12
to d3...@googlegroups.com
I'm trying to update a legend (a coloured rectangle and its label) in the following code, but I'm confused about the last 2 lines. Why does select("text") give me the desired result (all labels are updated), but not selectAll("text")? Shouldn't both return the same selection since I only have a single text element in each g element?


Thanks,
Kevin

Chris Viau

unread,
Nov 24, 2012, 3:00:27 PM11/24/12
to d3...@googlegroups.com
I was a little bit confused about your structure so I rewrote it another like in the general update pattern. http://jsfiddle.net/christopheviau/XYUL3/ It doesn't answer the question, but maybe it could help better understand what part of the data is bound to which elements contained in which selection.

kank

unread,
Nov 24, 2012, 4:37:57 PM11/24/12
to d3...@googlegroups.com
Thanks Chris. That helps me better understand what's going on.

legend.selectAll("text") is returning an array of 3 arrays (each with a single text element). legend.select("text") is returning a single array with the 3 text elements. The API reference doesn't seem to explain this difference.

Adding console.log(legend.select('text')legend.selectAll('text')); before the update seems to have changed the behaviour of the update actions -- selectAll("text") now gives the desired result. but I'm not sure why: http://jsfiddle.net/kankevin/TsBjp/

Sorry if my explanations are unclear (I'm a novice at programming).

Chris Viau

unread,
Nov 24, 2012, 5:32:19 PM11/24/12
to d3...@googlegroups.com
In fact, select( ) is what you want to use, since you want to update an array of 3 rects instead of 3 arrays of 1 rect:

    legend.select("rect")
        .attr("x"width 18)   
        .style("fill"color);        
        
    legend.select("text")
        .attr("x"width 24)
        .text(function(dreturn d});

And "legend" is in fact your update selection. So when you say console.log( legend.select('text') ), even if you are in a console.log argument, you are probably overriding this update code. 

Tore Nauta

unread,
Nov 25, 2012, 12:46:03 PM11/25/12
to d3...@googlegroups.com
Kevin, regarding your original question and fiddle:

// Why does "select" work, but not "selectAll"?
legend.selectAll("text").text(function(dreturn d});
legend.selectAll("rect").style("fill"color);

To summarize the observations: 

- the initial data has two elements
- the initial legend looks correct: 
    a) there are two legend elements and
    b) both fill and text are according to data

- the updated data has three elements
- the updated legend looks only partially correct:
    a) there are three legend elements and
    b) all three fill colors are correct, however
    c) the text is only correct in the last, just added, legend element


So, why is the fill color correct and the text isn't? And why is the text correct for the enter() selection, but not for the update() selection? This has not so much to do with what kind of selection is returned, but more with how bound data propagates through the document. 

In your code, the "fill" style update doesn't rely on bound data, because it directly uses the variable color. Therefore the color is always correct.

However, the text update does rely on the datum bound to the text element, which is a child of the g.legend element. When joining updated data, it is the g elements that receive the new data:

// Update legend
var legend svg.selectAll(".legend")
    .data(color.domain());

So, the question is how will the child text element receive this new data? There are only five methods in D3 that can affect the bound data, and selectAll is not one of those:
When a new g.legend element is created (enter), the text element is appended and both parent and child will own the same data. Therefore everything looked fine for all entered legend elements.

During update you used selectAll to change the text, and this operation will not copy data from parent to child. When you use selection.select it will copy data (note d3.select does not propagate data).

Tore


On Saturday, November 24, 2012 10:41:24 AM UTC-8, kank wrote:

kank

unread,
Nov 25, 2012, 6:51:17 PM11/25/12
to d3...@googlegroups.com
Thanks a bunch, guys.

Tore, your walkthrough of the select vs selectAll differences was great.

Kevin
Reply all
Reply to author
Forward
0 new messages