3

I am having a JSON data and i want to group by a field and then sort by the count.

var data = [{"Name":"Ravi","Country":"India"},
            {"Name":"Alex","Country":"USA"},
            {"Name":"Stew","Country":"UK"},
            {"Name":"Mary","Country":"India"},
            {"Name":"Raju","Country":"India"},
            {"Name":"Bill","Country":"UK"},
            {"Name":"Elisa","Country":"UK"},
            {"Name":"Sharma","Country":"India"}];

and my d3.js query is the following

var countryCount = d3.nest()
                    .key(function(d) { return d.Country; })
                    .rollup(function(a){return a.length;})
                    .entries(data);
console.log(JSON.stringify(countryCount));

and my output is

[{"key":"India","values":4},{"key":"USA","values":1},{"key":"UK","values":3}]

by my desired output is ( sorted by rollup value)

[{"key":"India","values":4},{"key":"UK","values":3},{"key":"USA","values":1}]

How can i do this? I know that the following browser default sort method also gives desired output. But just want to clear whether d3.js provides any inbuilt method to achieve this.

console.log(JSON.stringify(countryCount.sort(function (a, b){
    if (a.values > b.values) {return -1;} 
    else if (a.values < b.values) { return 1;} 
    else  return 0;
})));
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Sriram
  • 767
  • 2
  • 17
  • 42
  • 1
    you can use countryCount.sort(function (a, b){d3.ascending(a.values, b.values)}) – KennyXu Jun 25 '15 at 09:26
  • 1
    I know that the browser default sort method also gives desired output. But just want to clear whether d3.js provides any inbuilt method to achieve this. – Sriram Jun 25 '15 at 09:27
  • i don't think it's necessary. array.sort if simple, besides d3 did provide two help function d3.ascending and d3.decending. – KennyXu Jun 25 '15 at 09:30
  • even if d3.js provides `inbuilt sort` at the end its also gonna use the `native sort` method only, so doesnt really matter which one you use/choose. – vinayakj Jun 28 '15 at 18:23
  • Using .sortKeys() as suggested by Nisfan, worked for me. – Ola Karlsson Mar 13 '18 at 16:26

3 Answers3

5

D3 provide the condition, ascending descending and you can use inside on sort method. No worries You are using a native javascript method with nice stability

var countryCount = d3.nest()
                    .key(function(d) { return d.Country; })
                    .rollup(function(a){return a.length;})
                    .entries(data)
                    .sort(function(a, b){ return d3.ascending(a.values, b.values); })

console.log(JSON.stringify(countryCount));
Community
  • 1
  • 1
Raúl Martín
  • 4,471
  • 3
  • 23
  • 42
  • 2
    Although this answer was accepted by @SriramajeyamSugumaran as the correct answer, it does not show a way of d3 doing the sorting. The `sort()` method you applied is not one of d3's API but `Array.prototype.sort()` which was already mentioned by the OP. You are just putting `d3.ascending()` to use which, by looking at the documentation / implementation you linked to, is logically equivalent to the compare function in the question above. There is no built-in function which does sort the leaf nodes as requested. – altocumulus Jun 29 '15 at 23:24
  • 1
    In fact, it's the same solution proposed by @user1465639 in the first comment to the question, which was declined by OP as not being the desired d3-only approach. – altocumulus Jun 30 '15 at 09:53
  • I am here to help people, The only think that I am agree with you if bring part of the credit to @user1465639. The best option that you can do is improve your answer or said the part that I am wrong, this is the way to build a collaborative knowledge – Raúl Martín Jul 01 '15 at 09:30
  • 1
    Don't take it personally, it was not intended to offend you! The question clearly asked if there is a built-in solution to sort nested data, that ships with d3 . This core question was empasized using bold text. As far as I know, the answer to the question is "No, there is no such thing." The OP also stated to be aware of `Array.prototype.sort()` which was of no interest. As pointed out by my comment this is the approach you came up with. Probably, this was the reason why @SriramajeyamSugumaran revoked the acceptance of your answer as it does not directly address the question. – altocumulus Jul 01 '15 at 19:35
  • I don't take personally, maybe my English sound rude, sorry for that. But I insist if you have a better answer do it, If you have a correction to mine, edit it. Feel free, it is not the first time that this happened to me and it is not the first time that I remove a question because I consider that don't help to anybody, or another answer is better than mine. In my opinion the correct answer needs to be, the best way in d3 to sort elements if you don't have a specific way or functions in d3 to do it. And maybe the stability of 'sort' explain why the guys don't implement it. – Raúl Martín Jul 02 '15 at 08:43
  • 1
    this works, but it needs to be 'value' rather than 'values', so (a.value, b.value). Don't know if this is a change in d3 since the answer was posted. (plus I needed to make it d3.descending to get the biggest value first) – mgraham Aug 27 '20 at 13:03
1

No, there is no built-in function giving the result you are after. d3.nest() does have a methode nest.sortValues() which will sort the leaf elements of nested data, but this is meaningless in your case since you did apply .rollup() leaving you with just one leaf per key. As you already mentioned, the way to go is using Array.prototype.sort().

altocumulus
  • 21,179
  • 13
  • 61
  • 84
0

d3 provides a method sortKeys in nest function which will sort your nested list based on the key you selected. You can pass d3.ascending or d3.descending based on your requirement.

From your example:

var countryCount = d3.nest()
                    .key(function(d) { return d.Country; })
                    .sortKeys(d3.ascending)
                    .entries(data);

which will give you:

[{"key":"India","values":4},{"key":"UK","values":3},{"key":"USA","values":1}]
Nisfan
  • 149
  • 3
  • 15
  • 1
    Yeh, but that's sorting by key: India -> UK -> USA. It's just coincidental it matches the 4 -> 3 -> 1 sorting wanted for the value field – mgraham Aug 27 '20 at 13:02
  • why can't you rollup first then sort based on 'value'? It should solve your problem. – Nisfan Nov 05 '20 at 13:52