d3 selectAll: count results
Asked Answered
G

4

32

How do I count how many nodes were matched by a selectAll? (without joined data)

Or if there's data, how to count the data from the selection? (suppose I've set it with "data(function...)" so I don't know the length in advance)

Gules answered 3/7, 2015 at 14:15 Comment(1)
Use selection.size() to get the size of a selection.Bridgeboard
M
62

Just use d3.selectAll(data).size().Hope this example help you:

 var matrix = [
   [11975,  5871, 8916, 2868],
   [ 1951, 10048, 2060, 6171],
   [ 8010, 16145, 8090, 8045],
   [ 1013,   990,  940, 6907]
 ];

 var tr = d3.select("body").append("table").selectAll("tr")
            .data(matrix)
            .enter().append("tr");

 var td = tr.selectAll("td")
          .data(function(d) { return d; })
          .enter().append("td")
          .text(function(d) { return d; });
 var tdSize=tr.selectAll("td").size();

Complete jsfiddle here.

Meier answered 4/7, 2015 at 13:41 Comment(0)
M
2

If you want the length conveniently from a callback function, such as setting an element attribute, it seems that you can get it from the third argument, like so:

node
    .attr('some-property', function(datum, index, array) {
        // d/datum = the individual data point
        // index = the index of the data point (0, 1, 2, 3, etc)
        // array = full array of data points
        // array.length = the size/length of the data points / dataset
        
        // some calculation involving array.length or whatever
        return someValue;
    });

Similar to the call signature of the JavaScript forEach/filter/etc. array functions.

Seems like most of the d3 functions support this:

https://github.com/d3/d3-selection

...current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element (nodes[i])

...is a repeated phrase throughout the docs. So if you see a d3 function where you'd use d, you can probably also get index and array.

Musty answered 22/4, 2019 at 15:33 Comment(0)
D
1

One way I have done this previously is to pass that information into the data function by making a new object.

 .data(function(d) {         
     return d.Objects.map(function(obj) {
         return {
             Object: obj,
             TotalObjects: d.Objects.length
         }
   });

Then in your update portions you use Object and still have the count available.

.attr("x", function(d) {

    return d.Object.X;
 })
 .attr("y", function(d) {

    return d.TotalObjects;
 })
Disused answered 3/7, 2015 at 14:37 Comment(0)
T
1

To get the data count, then after .selectAll() and .data(), it appears that .enter() is needed before .size():

legend_count = legendBoxG.selectAll("legend.box")
                         .data(curNodesData, (d) -> d.id)
                         .enter()
                         .size()

Without the .enter(), the result is 0. The .enter() makes it return the data count. (Code above is shown in Coffee dialect.)

I need to get the count before adding attributes to my svg objects (in order to scale them properly), and none of the preceding examples did that. However I can't seem to add more attributes after stripping out the count into a variable as above. So while the above approach demonstrates the operation of data() and enter() it isn't really a practical solution. What I do instead is to get the length of the data array itself before doing the selectAll(). I can do that most simply with the length property (not a function) on the data array itself:

 legend_count = curNodesData.length
Tangential answered 26/5, 2016 at 23:56 Comment(1)
I don't know why size() is giving you zero at times, but it's not true in general that enter() is needed before size(): d3.selectAll("h1").size() yields 1 for me on a page that has one <h1>.Steenbok

© 2022 - 2024 — McMap. All rights reserved.