I've created a set of d3js elements based on an array of 3 elements:
var data = [[0,0,2],[0,23,5],[2,12,5]]; circleSet = svg.selectAll() .data(data) .enter().append('circle');
edit:
How can I select the second element by index?
The most natural way to manipulate just one element is using the filter function:
var data = [[0,0,2],[0,23,5],[2,12,5]]; var circleSet = svg.selectAll() .data(data) .enter() .append('circle'); var filteredCircleSet = circleSet .filter(function (d, i) { return i === 1;}) // put all your operations on the second element, e.g. .append('h1').text('foo');
Note that depending on what you do with the other elements you might use one of the two variants of this approach:
variant a): use the filter in the data function (to reduce the data and the appended elements)
variant b): use the filter to exclude instead of to include in order to remove the other elements at the end
See also Filter data in d3 to draw either circle or square
One other way to do it is to use the selection.each method: https://github.com/mbostock/d3/wiki/Selections#wiki-each By using an if statement with the corresponding index you can create a block for one element. E.g.
var data = [[0,0,2],[0,23,5],[2,12,5]]; var circleSet = svg.selectAll() .data(data) .enter() .append('circle') .each(function (d, i) { if (i === 1) { // put all your operations on the second element, e.g. d3.select(this).append('h1').text(i); } });
In d3 v4 and above, you can use Selection.nodes()
. Assuming i
is the index number you want:
d3.select(someSelection.nodes()[i])
It's a natural one-liner, and it's arguably more readable: you're obviously just getting the node at i
in the order, as a D3 selection.
It looks like it'd be more efficient than the alternatives, which involve looping through the entire selection with .each()
. So, you might think this is O(1), while the other options are O(n).
Unfortunately, Selection.nodes() itself includes an each
loop, so it's also O(n) (not that it's likely to matter in real life unless you call this thousands of times on selections with thousands of nodes):
var nodes = new Array(this.size()), i = -1; this.each(function() { nodes[++i] = this; }); return nodes;
However, this way you can separate the looping from the getting, which could be useful if efficiency is a major concern.
For example, if you want to loop through each()
in selection A and get the item in the same position from selection B, and you want to avoid loops-within-loops because those selections can be huge and you call this many times, you could structure it like this, which would be O(2n) instead of O(n^2):
var selectionBArray = selectionB.nodes() selectionA.each(function(d, i) { var iFromSelectionA = this var iFromSelectionB = d3.select(selectionBArray[i]) })
...or if you're using arrow functions to preserve this
context:
var selectionBArray = selectionB.nodes() selectionA.each((d, i, nodes) => { var iFromSelectionA = d3.select(nodes[i]) var iFromSelectionB = d3.select(selectionBArray[i]) })
You could even (ab)use Selection._groups
, but I wouldn't recommend using a private property like that since it'll break if a D3 update renamed the _groups
property, like this update did.
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