First off: I love D3. It's amazing. And makes me wish I knew JS better. Hope someone out there can help me!
I've been working on a multi-variable, zoomable, sunburst+icicle diagram. For reference, I've been inspired by the following:
I've recently been looking into adding a real-time component: I've integrated a real-time data feed (via MQTT) into my JS code, and it is receive/reading data from a source and adding to the hierarchical data. Essentially, I am continually adding to the data that builds my sunburst, redrawing the sunburst every 2 secs, and I'm wondering the best way to do it.
Pre-real-time, I started off reading a static JSON file, using d3.json to load the JSON file, and then calling d3.hierarchy on that, which eventually I pass to d3.partition.  Note: because I have multiple values/variables, I need to run partition multiple times to get the different sized arcs, and then tween between them.  This seemed to work fine.  Example here.
But now that I'm constructing the Hierarchy + Partitions over and over, every 2 seconds, as data is loaded in from the back, I'm wondering: is it better to create a new hierarchy (d3 Node tree) every time from my data, or to construct the hierarchy myself?
I'm specifically concerned about how the select.join() works (for tweening between the arcs of the previous and new values), and how d3 knows which Nodes are new vs. not?  If I run d3.hierarchy() every time, then every Node is new (right?), and so how does enter-vs-update work?  Even though the source data is the same (albeit with different values, due to real-time updates).  I don't think there's a publicly documented way of creating "new Node()", or how to maintain/add to a tree of Nodes, but seems that would be a more efficient option than running d3.hierarchy every couple seconds.
I hope I've explained myself clearly? Just looking for some expert guidance. Thanks!
When you call .data() you can give a second parameter that tells D3 how to identify each item.  For example .data(mydata, d => d.data.id) says to use the id field to identify each node.
Then, when .join() comes into play, it will look at this value and compare it to what is attached to each node.  Any new values not seen on any nodes will go to enter, and those values that are found on existing nodes will go to update.
The only trick with this is to make sure the value you specify will be definitely be unique, and won't change between calls.  For example if you do something like .data(mydata, d => d.data.surname) and you get two items with the same surname, the enter/update will give unpredictable results.  Likewise if you do .data(mydata, d => d.data.randomValue) then items will never get updated because the value will always be different between each call - the nodes will be removed via exit then recreated via enter, rather than left in place but modified by update, as a different value makes D3 treat them as new nodes instead of identifying them as existing ones.
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