11

私は時間レポートアプリケーションのd3.js視覚化に取り組んでいます。プロジェクト時間レポートを含む配列actualsに行データがあります(簡略化):

[{  resource: "John Smith",
    reporting_period: "2012/04/1",
    project: "Java implementation",
    hours: 8} 
 ... }]

d3.nest演算子を使用して、プロジェクトの実績をプロジェクト、リソース、および期間ごとに階層的にグループ化しようとしています。すべてがうまく機能しますが、 nest.rollup()演算子を使用して、グループ化の中間レベルで時間の小計を取得する方法を見つけることができません。

私は次のようなものを持っています:

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);

ただし、 tot_hoursはリーフレベルでのみ返されます。d3.nestのみを使用してこれにアプローチする方法に関するアドバイスはありますか?

4

1 に答える 1

6

ドキュメントから:

nest.rollup(関数)

リーフ 要素の各グループに適用されるロールアップ関数を指定します。ロールアップ関数の戻り値は、マップ演算子によって返される連想配列、またはエントリ演算子によって返される各エントリのvalues属性のいずれかでリーフ値の配列を置き換えます。

ご覧のとおり、ロールアップはリーフ要素で機能します。データを複数のレベルでネストすることで、これを回避できます。

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);

しかし、これは大規模なデータセットでは非常に非効率的です。nest()それ以外の場合は、関数を使用してすべての中間レベルを作成することをお勧めします。次に、独自の再帰関数を使用して合計時間を集計できます。擬似コード:

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 
}
于 2015-07-21T22:59:22.890 に答える