Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

d3.layout.hierarchy: Allow internal nodes to have value #574

Closed
wants to merge 2 commits into from

Conversation

loganlinn
Copy link

This adds the ability for the internal nodes to contribute to their value, instead of their value being entirely composed of their children's values.

Adds a new method to d3.layout.hierarchy() to set internal_value in a similar fashion that you set the value for leaf nodes. When recursing, check to see if there's a function for internal_value, if there is, call it.

I am new to d3, so I apologize if this is already do-able, or if I left anything out.

This adds a new method to d3.layout.hierarchy() to allow internal nodes
to have a value which is added to the combined values of its children.

The internal_value is identical to hiearchy.value([value]), but is only
called for internals nodes.
@olgasson
Copy link

Hi,

I am interested in this feature. Any news about that?

@loganlinn
Copy link
Author

It is working in my branch. I suppose it could use some extra documentation to be more merge-worthy, but I have not gotten any feedback from the maintainers...

@olgasson
Copy link

Can you provide a minimal working example, using JSON? How do I have to define the internal value in the JSON object?

What would I need to change, if I just like to overwrite the "value" as soon as an internal_value is defined?

@loganlinn
Copy link
Author

Take, for example, the Sunburst demo: http://mbostock.github.com/d3/ex/sunburst.html

The data for that graph is: http://mbostock.github.com/d3/data/flare.json

Instead, consider it being something like:

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "size": 5000,
   "children": [
    {
     "name": "cluster",
     "size": 5000,
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "HierarchicalCluster", "size": 6714},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "size": 5000,
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731},
      {"name": "MaxFlowMinCut", "size": 7840},
      {"name": "ShortestPaths", "size": 5914},
      {"name": "SpanningTree", "size": 3416}
     ]
    },
    {
     "name": "optimization",
     "size": 5000,
     "children": [
      {"name": "AspectRatioBanker", "size": 7074}
     ]
    }
   ]
  },

Notice: nodes that had children now also have a size (an internal value).

To include those values in the calculated value of the internal node, you'd would do something like:

var nodeSize = function(d) { return d.size; };
var partition = d3.layout.partition()
    .sort(null)
    .size([2 * Math.PI, radius * radius])
    .value(nodeSize)           // include leaf node values
    .internal_value(nodeSize); // include internal node values

@evenwestvang
Copy link

+1 for supporting something like this. Much needed when stuck with a data set where not only leaf nodes carry values.

@eparejatobes
Copy link

+1 here too!

@eparejatobes
Copy link

is this in 3.0?

@mbostock
Copy link
Member

@eparejatobes Nope, sorry.

@mbostock
Copy link
Member

One potential issue is the the likelihood of collision between the node’s internal value and the node’s aggregate value computed by the layout. Currently that aggregate value is stored back as node.value after being computed, so using function(node) { return node.value; } as the internal value property accessor would overwrite the internal value with the aggregate value, and thereby cause problems if the layout was computed multiple times on the same input dataset.

An alternative solution for this problem is to use dummy nodes that are present in the dataset but not displayed. These dummy nodes are a child of the node with an internal value, have no children themselves, and are marked (e.g., node.dummy is true) so that they can be ignored during rendering.

@loganlinn
Copy link
Author

One potential issue is the the likelihood of collision between the node’s internal value and the node’s aggregate value computed by the layout

Ah, that's unfortunate. Storring the aggregate value at node.value further constricts the design to not allow internal nodes to have their own value. Unless this is the intent of node design, it would seem reasonable to store the aggregate value under a different property; it's a caching mechanism, correct?

Thanks for the great library btw!

@mbostock
Copy link
Member

The reason value is used is for simplicity—you can refer to a leaf’s value and an internal node’s aggregate value the same way. I prefer not to come up with a new name if I can avoid it. :)

Using value doesn’t prevent nodes from having an internal value, but it does require that the internal value be stored on a differently-named property than the computed aggregate value. This is not an issue when only leaf nodes have values because the two are identical.

For example, if you defined the value as function(d) { return d.size; }, as in the examples, then value refers to the computed aggregate value and size returns to the internal value. Or you could use nodeValue or internalValue if you prefer something more explicit. For that matter you could use function(d) { return +d; } and then have nodes implement object.valueOf.

@Kallin
Copy link

Kallin commented Jul 31, 2014

This would be hugely valuable! Currently it seems I'm forced to fill in the blanks on leaf nodes with an 'other' category so that things add up. I'd prefer to simply specify the value of each node, and have it error out if a node happens to have children who's sum exceed it's own value. Working on an icicle chart, something like this: http://codepen.io/Kallin/debug/vzgnF. Cheers!

@mbostock mbostock modified the milestones: 3.x, 4.0 Oct 22, 2015
@mbostock
Copy link
Member

This has been implemented in d3-hierarchy for 4.0!

@mbostock mbostock closed this May 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

6 participants