In the answer Mike posted here, he overviews three different ways to apply a change to a matched element based on a index or custom filter. I'm trying to clarify, hopefully for more people than just myself, the actual selections in these solutions.
So given a document with 6 SVG rects with class .bar
, we have these different selections and what they return:
d3.select(".bar"):
[Array[1]
0: rect.[object SVGAnimatedString]
length: 1
parentNode: html
__proto__: Array[0]
d3.selectAll(".bar"):
[Array[6]
0: rect.[object SVGAnimatedString]
1: rect.[object SVGAnimatedString]
2: rect.[object SVGAnimatedString]
3: rect.[object SVGAnimatedString]
4: rect.[object SVGAnimatedString]
5: rect.[object SVGAnimatedString]
length: 6
parentNode: html
__proto__: Array[0]
$(".bar"):
[
<rect class="dataBars" x="53.191489361702125" width="212.7659574468085" y="4.761904761904762" height="11.11111111111111"></rect>,
<rect class="dataBars" x="74.46808510638297" width="372.3404255319149" y="20.634920634920636" height="11.11111111111111"></rect>,
<rect class="dataBars" x="127.6595744680851" width="212.7659574468085" y="36.507936507936506" height="11.11111111111111"></rect>,
<rect class="dataBars" x="31.914893617021274" width="212.7659574468085" y="52.38095238095238" height="11.11111111111111"></rect>,
<rect class="dataBars" x="159.5744680851064" width="265.9574468085106" y="68.25396825396825" height="11.11111111111111"></rect>,
<rect class="dataBars" x="234.04255319148936" width="138.29787234042553" y="84.12698412698413" height="11.11111111111111"></rect>,
]
Now here's where it get's more tricky (for me at least), say I want to apply a style
to the 3rd rectangle, this rectangle can be found using
d3.selectAll(".bar")[0][2]
But if we want to then use the d3.selection.attr()
, that returns
TypeError: Property 'style' of object #<SVGRectElement> is not a function
But we can then wrap this selection
d3.select(d3.selectAll(".bars rect")[0][2]).style("fill", "red")
and this will work as expected.
Then, if we want to apply a filter, such as
filter(function (d) { return d === 5 || d === 15;}
the d3.selectAll(".bar")
must be used, and d3.select(d3.selectAll(".bar"))
will not work correctly.
I've read Mike's excellent tutorials and documentation on selections, but just when I think I have it figured out, something pops up and surprises me. So what is the difference between these selections, and how do I know which one to use when? Thank you very much, and sorry for the long post!
I've tried to do this in the past and run into similar errors. Then I realized that I was not really following the intended API. The second that you start accessing selection elements by index, you're way off the beaten path.
See nested selections
So, if you wanted to style your third bar, you would do
d3.selectAll(".bar").style("color", function(d,i) { return i === 2 ? "red" : null; } )
And if your selection is one level more nested than that, make it function(d,i,j)
and similarly go from there. Etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With