1

I want to be able to implement the D3 General Update Pattern III as a D3 pack layout. This means that each char would be inside a circle and that the char circles would be inside a larger enclosing circle. Everything should stay consistent with the GUPIII except that, of course, the positioning of the chars will be in a larger circle instead of on a horizontal axis.

I have tried to follow the same GUPIII structure including the important aspect of using a data join with key.

var alphaBubble = d3.layout.pack()
    .size([diameter, diameter])
    .padding(5);

var nodes = alphaBubble.nodes(data);

var vis = svg.selectAll("circle")
    .data(nodes, function(d) { return d; });

But data join with key does not seem to work with the pack layout.

I'm having trouble getting my head around possible alternative mechanisms such as pack.value or nest. I have not been able to grasp whether they would somehow accomplish what is going on in GUPIII where incoming (enter) chars are green, existing (update) chars are black, exiting chars are removed.

Join by key is important in order to maintain the relative position of the char. I realize that this aspect of relative position is not as easy to see in the pack layout as it is in the linear axis layout, but I have a necessity for this which is not apparent in this example. I just need to successfully implement a "by key" join with pack that retains existing nodes when new data comes in.

Typically what I see with the pack layout is that either no nodes are replaced on data updates (maybe only attributes such as size are altered), or else all nodes are replaced with new incoming data, depending on the context. But I want to retain the nodes that are the same (by some key, in this case the char itself), remove the ones that are no longer present, and add the new ones "by key". Can anyone help me translate the D3 General Update Pattern II to a pack layout? I would include my full code attempt, but I really think just looking at the GUPIII is more clear if you are familiar with how the pack layout can facilitate join by key on update.

Thank you.

Richard Walker
  • 187
  • 1
  • 2
  • 11
  • See https://stackoverflow.com/questions/14794133/update-a-layout-pack-in-d3-js and https://stackoverflow.com/questions/18790941/updating-the-data-of-a-pack-layout-from-json-call-and-redrawing and https://stackoverflow.com/questions/11801674/updating-d3-circle-pack-layout – Lars Kotthoff Feb 03 '16 at 22:10
  • @Lars pack.value seems to only affect circle size, but I need to dynamically change color. And it is unclear to me whether or how selection.datum might be used to update color. – Richard Walker Feb 03 '16 at 23:23
  • Updating the data and display are completely separate. Once you've bound the new data, you can do whatever you want to update the color. – Lars Kotthoff Feb 03 '16 at 23:27
  • @Lars but per my previous comment, I don't want to completely replace my data with each update. I will need to retain some and update its visual representation, some I will need to remove, and some will be new. This is the enter/update/exit pattern. Update by key would support this as it does in GUPII, but pack layout does not seem to support data join by key. Am I wrong? – Richard Walker Feb 04 '16 at 02:49
  • Ok, well, It turns out that data join by key _does_ work in the pack layout. I discovered I need to return d.char from the key function instead of just d. – Richard Walker Feb 04 '16 at 03:29
  • Great, so the problem is solved? Note that the way D3 joins data is completely independent of any layout, so there's no need for the pack layout to "support" data joins. – Lars Kotthoff Feb 04 '16 at 04:30
  • Would you mind posting an answer with the solution then so the question doesn't appear to be unanswered please? – Lars Kotthoff Feb 04 '16 at 06:34
  • Yes, will do shortly. I am finalizing my code solution for a pack version of the General Update Pattern III (with key joins on update) and will also link to my code. – Richard Walker Feb 05 '16 at 16:47

1 Answers1

1

Ok, through much trial and error and study of existing examples I have been able to solve my question as to how to implement the D3 General Update Pattern III as a pack layout. I was not able to find any example that used data join by key, which is necessary for object constancy on update, so I'm hoping my example may provide some guidance for others who need the same pattern of behavior.

My solution is here. And my Javascript code is here.

I will point out a few important highlights. First, unlike in the linear non-pack version, the data join-by-key value must be accessed as an object property (i.e. d.id) instead of directly (i.e. d).

// Data join by key to <g> nodes
var node = svg.selectAll(".node")
    .data(nodes, function(d) {
        return d.id; 
    });

// Data join by key to circles
var circles = svg.selectAll("circle")
    .data(nodes, function(d) {
        return d.id; 
    });

Next, since the alphabet character is represented in a circle, both the circle and the char must be contained in a <g> element, i.e. node. And here was the trickiest part: the data needs to be joined by key separately to both the node and the circle elements. This is because the pack layout has performed the necessary calculation of scale (i.e. circle radii) and coordinate positions. So the circles need the data's calculated radii and the <g> node elements need the calculated coordinate positions. So a separate data join was required for each.

Once I figured this out, all of the necessary operations and references fell into place and the pack version of the General Update Pattern started working properly. Be sure to compare the linear and pack versions to each other.

The alphabetization sort is, I guess, unnecessary since the pack layout makes no accommodation for ordering. But I retained the sorting for consistency and because I wanted to observe its effect.

Richard Walker
  • 187
  • 1
  • 2
  • 11