Skip to content
This repository has been archived by the owner on Jul 29, 2019. It is now read-only.

Network: force array order when sorting hierarchical levels #3576

Merged
merged 5 commits into from
Oct 20, 2017

Conversation

wimrijnders
Copy link
Contributor

@wimrijnders wimrijnders commented Oct 15, 2017

Fixes #3403.
Fixes #3542.

If coordinates are not available to sort within a hierarchical level, sort to array order instead.

The previous fix on this issue was not good enough to circumvent this quirk in the chromium sorting. This should bury it.

Fixes #340r34.

If coordinates are not available to sort within a hierarchical level, sort to array order instead.

The previous fix on this issue was not good enough to circumvent this quirk in the chromium sorting. This should bury it.
// Test on 'undefined' takes care of divergent behaviour in chrome
if (a.y === undefined || b.y === undefined) return 0; // THIS HAPPENS
if (a.y === undefined || b.y === undefined) {
return idOrder[a.id] - idOrder[b.id];
Copy link
Contributor

@macleodbroad-wf macleodbroad-wf Oct 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you use return nodeArray.indexOf(a) - nodeArray.indexOf(b) instead of creating idOrder?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my first attempt. It doesn't work because the array get changed inline as the sorting runs.

So the indexing may change on every call to the custom sort() - and it does on chrome, even if there's no reason to change it. That's the quirk this issue tries to work around.

Basically, the fix is to register the initial sorting order and retain that by default.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the x or y values ever undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They come from the options. They are user-defined starting positions, not required. They can be undefined for that reason.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am somewhat uncomfortable with the idea of having to iterate this array twice in order to sort it.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user specifies an undefined position, can we assign it a position, so that by the time it reaches this sort code, it'll never be undefined?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about just comparing a.id against b.id in the case that x or y is undefined?

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 15, 2017 via email

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 15, 2017 via email

@mbroad
Copy link

mbroad commented Oct 15, 2017

Related issue https://bugs.chromium.org/p/v8/issues/detail?id=90 for reference.

@mbroad
Copy link

mbroad commented Oct 15, 2017

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 15, 2017 via email

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 15, 2017 via email

@macleodbroad-wf
Copy link
Contributor

It's true that the ids are not guaranteed to sort in an expected order, but the example shown uses sortable ids, and I think that is what most people use (ie, monotonically increasing integers). So we should optimize for that case.

Optionally we could provide a way for users to use stable versions of these sorting strategies, that take the performance hit, while others, who do not have the same problem will not take any additional performance hit.

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 15, 2017

I think that is what most people use (ie, monotonically increasing integers). So we should optimize for that case.

No, sorry, disagree with this. Users insert what they damn well please. Integers is just a very special case.

Optionally we could provide a way for users to use stable versions of these sorting strategies

Hokay, this could be workable. So adding an option to be able to select a stable sort.
Another option is to find a really fast js implementation and use that instead. Perhaps wishful thinking? I'll google around now.


@macleodbroad-wf
Copy link
Contributor

macleodbroad-wf commented Oct 15, 2017

Unfortunately we do not have the actual data to back up how users id their nodes in the wild. However, if it's going to be arbitrarily sorted anyways, making it sort consistently for integer-based ids makes sense to me - especially given the issue reporter's example.

From what I've read, timsort is the best alternative... However, even it has 38% slow-down. I agree with the decision of the Chrome team to provide a fast unstable sort as the default.

edit: Also to note, the vast majority of our network examples, themselves also use monotonically increasing integers as ids.

@wimrijnders
Copy link
Contributor Author

Unfortunately we do not have the actual data to back up how users id their nodes in the wild.

Well, I've got a pretty clear idea from all the examples I've collected from the issues. From my point of view, integer id's are the exception. You want me to take samples from the code of 76 issues I have at hand?

I just added some links to previous comment; perhaps they are of use. First link appears to be more efficient that what I have thought up. The other two just look interesting.

@macleodbroad-wf
Copy link
Contributor

I'd like to throw https://www.npmjs.com/package/timsort into the running (benchmarks included on the page)

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 15, 2017

Yeah. That looks good.

Edit: Very good indeed. Not only stable, but faster than default sort, at least in node.js. That's two reasons for using it.

If this beats chrome's sort, then it's a no-brainer.

@wimrijnders
Copy link
Contributor Author

Ah nice, the benchmark is on github. We will test this in chrome.

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 16, 2017

Here are the results of the timsort benchmark when run on chromium. Compare these with the values on the timsort page.

ArrayType                     Length TimSort   array.sort  Speedup
randomInt                     10     812       1009        1.2434146066211673
randomInt                     100    8540      4717        0.5524051126935311
randomInt                     1000   118381    59342       0.5012829312070081
randomInt                     10000  1457349   4293133     2.9458492011760473
descendingInt                 10     562       1463        2.6001051283441825
descendingInt                 100    990       10056       10.157394158751922
descendingInt                 1000   3126      166638      53.30307876796892
descendingInt                 10000  27500     2577566     93.72969696891316
ascendingInt                  10     741       1102        1.48623291403758
ascendingInt                  100    1130      10230       9.047387427267074
ascendingInt                  1000   3758      168373      44.79514466122507
ascendingInt                  10000  28766     2407033     83.67439165623504
ascending3RandomExchangesInt  10     824       1173        1.4232006910845008
ascending3RandomExchangesInt  100    1922      10480       5.452377855918806
ascending3RandomExchangesInt  1000   5891      170291      28.905792488695706
ascending3RandomExchangesInt  10000  44366     2431466     54.8039068368716
ascending10RandomEndInt       10     968       1459        1.5077770604740948
ascending10RandomEndInt       100    2504      12416       4.958007520053549
ascending10RandomEndInt       1000   7671      166860      21.751344304845748
ascending10RandomEndInt       10000  53616     2326699     43.3950885916376
allEqualInt                   10     749       1075        1.4357880569226662
allEqualInt                   100    1123      2414        2.149150782468075
allEqualInt                   1000   3933      15872       4.034953924340162
allEqualInt                   10000  30650     148133      4.833061446428325
manyDuplicateInt              10     931       1426        1.5313993235105956
manyDuplicateInt              100    8209      13010       1.5847781071129106
manyDuplicateInt              1000   109587    195935      1.7879320177946991
manyDuplicateInt              10000  1387483   2700683     1.9464618193616947
someDuplicateInt              10     957       1407        1.469996605358849
someDuplicateInt              100    8370      12928       1.5445712123971784
someDuplicateInt              1000   109951    193346      1.758472504859978
someDuplicateInt              10000  1400416   2647250     1.8903302588522226

Not too shabby. Most speedups are less than with node.js, but I suspect that's the google developers are doing a better job at sorting. On the whole, it's a gain.
Edit: Actually, node.js also uses V8, same as chrome, so that the values should be comparable. Perhaps it's my imagination that chrome performs better.

@wimrijnders
Copy link
Contributor Author

wimrijnders commented Oct 16, 2017

While I'm at it, here are the values for firefox.

ArrayType                     Length TimSort   array.sort  Speedup
randomInt                     10     425       845         1.9875580461234132
randomInt                     100    7160      7439        1.0389516682764817
randomInt                     1000   93442     96121       1.028667362281608
randomInt                     10000  1196216   1313066     1.0976829727055877
descendingInt                 10     245       674         2.7466001966968503
descendingInt                 100    1644      4151        2.524041141007176
descendingInt                 1000   12180     47897       3.932471264366038
descendingInt                 10000  117516    647433      5.509289462489311
ascendingInt                  10     132       365         2.759715535419072
ascendingInt                  100    686       1760        2.56217396579009
ascendingInt                  1000   3821      25473       6.666339548596877
ascendingInt                  10000  30333     248116      8.179670329679569
ascending3RandomExchangesInt  10     264       664         2.51461379516853
ascending3RandomExchangesInt  100    1733      3832        2.2113563152102715
ascending3RandomExchangesInt  1000   6212      44614       7.181488933601303
ascending3RandomExchangesInt  10000  42066     521183      12.38946117273561
ascending10RandomEndInt       10     470       849         1.8044713001603132
ascending10RandomEndInt       100    2081      4480        2.1523801897787744
ascending10RandomEndInt       1000   6983      43262       6.194737784121725
ascending10RandomEndInt       10000  44433     589250      13.261440360109248
allEqualInt                   10     140       439         3.1253664169550337
allEqualInt                   100    797       1849        2.3199540085729513
allEqualInt                   1000   4017      23721       5.904480398251089
allEqualInt                   10000  30550     250083      8.186033824314205
manyDuplicateInt              10     572       912         1.593256611271726
manyDuplicateInt              100    10829     7712        0.7121805575863754
manyDuplicateInt              1000   136344    99524       0.7299497598005458
manyDuplicateInt              10000  1404733   1292216     0.9199017607137718
someDuplicateInt              10     561       841         1.5001633817054976
someDuplicateInt              100    10862     7642        0.703608801055636
someDuplicateInt              1000   137305    97024       0.7066385055165223
someDuplicateInt              10000  1443833   1368566     0.9478702527993484

Interestingly, firefox does a better job at sorting than chrome.

@wimrijnders
Copy link
Contributor Author

It looks like timsort is abandonware, though. No PR's or issues processed since October '16. Not a good sign.

@mbroad
Copy link

mbroad commented Oct 16, 2017

That's true, but it is a fairly straightforward implementation of a well-known algorithm.

@wimrijnders
Copy link
Contributor Author

OK made the switch. Interestingly, there was only one other location within Network where sorting was used.

Copy link

@mbroad mbroad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple nits, otherwise looks good.

* even if the custom sort function returns 0.
*
* For this reason, an external sort implementation is used,
* which has the added benefit of being faster of the standard
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"... of being faster than the ..."

@@ -30,6 +29,8 @@
* The layout is a way to arrange the nodes in the view; this can be done
* on non-hierarchical networks as well. The converse is also possible.
*/
'use strict';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why move this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No special reason, other than to keep the javascript code together. You'd rather have it on top?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine as is, just curious

@yotamberk yotamberk merged commit 88f0a6a into almende:develop Oct 20, 2017
@wimrijnders wimrijnders deleted the issue3404 branch October 21, 2017 04:56
mojoaxel pushed a commit to visjs/vis_original that referenced this pull request Jun 9, 2019
…3576)

* Network: force array order when sorting hierarchical levels

Fixes #340r34.

If coordinates are not available to sort within a hierarchical level, sort to array order instead.

The previous fix on this issue was not good enough to circumvent this quirk in the chromium sorting. This should bury it.

* Added TimSort for sorting in DirectionStrategy

* Added TimSort to LayoutEngine

* Fixed typo
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants