I am working on a d3.js visualization for a time reporting application. I have row data in an array actuals containing project time reports (simplified):
[{ resource: "John Smith",
reporting_period: "2012/04/1",
project: "Java implementation",
hours: 8}
... }]
I am trying to use the d3.nest operator to group the project actuals hierarchically by project, resource and period. Everything works great but I cannot find a way to get the subtotals of hours at the intermediate levels of the grouping using the nest.rollup() operator.
I have something like:
actuals_by_prj_rsrc_period = d3.nest()
.key(function(d) { return d["project"]; })
.key(function(d) { return d["resource"]; })
.key(function(d) { return d["reporting_period"]; })
.rollup(function(rows) {return {
tot_hours:d3.sum(rows, function(d) {return d["hours"];}),
actuals: rows
};})
.entries(actuals);
but it returns tot_hours only at the leaf level. Any advice on how to approach this using only d3.nest?
I am working on a d3.js visualization for a time reporting application. I have row data in an array actuals containing project time reports (simplified):
[{ resource: "John Smith",
reporting_period: "2012/04/1",
project: "Java implementation",
hours: 8}
... }]
I am trying to use the d3.nest operator to group the project actuals hierarchically by project, resource and period. Everything works great but I cannot find a way to get the subtotals of hours at the intermediate levels of the grouping using the nest.rollup() operator.
I have something like:
actuals_by_prj_rsrc_period = d3.nest()
.key(function(d) { return d["project"]; })
.key(function(d) { return d["resource"]; })
.key(function(d) { return d["reporting_period"]; })
.rollup(function(rows) {return {
tot_hours:d3.sum(rows, function(d) {return d["hours"];}),
actuals: rows
};})
.entries(actuals);
but it returns tot_hours only at the leaf level. Any advice on how to approach this using only d3.nest?
Share Improve this question asked Nov 1, 2012 at 21:16 Paolo BozzolaPaolo Bozzola 1,1532 gold badges10 silver badges14 bronze badges 1-
What exactly do you want to pute
tot_hours
? Is it the aggregate number of hours across all previous reporting periods? Are you grouping by resource? By project? – Renaud Commented Oct 22, 2013 at 13:48
1 Answer
Reset to default 6from docs:
nest.rollup(function)
Specifies a rollup function to be applied on each group of leaf elements. The return value of the rollup function will replace the array of leaf values in either the associative array returned by the map operator, or the values attribute of each entry returned by the entries operator.
As you can see rollup works with leaf elements. You could bypass this by having data nested at multiple levels:
function nest(keys, data, rollupFunc) {
var nst = d3.nest();
keys.forEach(function(key) {
nst.key(function(d) { return d[key]; });
});
if (rollupFunc) {
nst.rollup(rollupFunc);
}
return nst.entries(data);
}
var rollupFunction = function(d) {
return {
"total_hours": d3.sum(d, function(dd) { return dd["hours"]})
}
}
var rez1 = nest(["project", "resource"], actuals);
var rez2 = nest(["project"], actuals, rollupFunction);
var rez3 = nest(["project", "resource"], actuals, rollupFunction);
But this very inefficient for larger data sets. Otherwise I would suggest using nest()
function to create all intermediate levels. Then you could aggregate total hours using your own recursive function. Pseudocode:
function aggregate(node) {
if (node has property total_hours) {
return total_hours
}
sum = 0
foreach child in data.values {
sum += aggregate(child)
}
node.total_hours = sum
return node.total_hours
}