コンテンツにスキップ

階層

階層レイアウトを計算する前に、ルートノードが必要です。データがJSONなどの階層形式ですでに存在する場合は、hierarchyに直接渡すことができます。そうでない場合は、カンマ区切り値(CSV)などの表形式データをstratifyを使用して階層に再配置できます。

hierarchy(data, children)

· ソース · 指定された階層データからルートノードを構築します。指定されたデータは、ルートノードを表すオブジェクトである必要があります。例えば

js
const data = {
  name: "Eve",
  children: [
    {name: "Cain"},
    {name: "Seth", children: [{name: "Enos"}, {name: "Noam"}]},
    {name: "Abel"},
    {name: "Awan", children: [{name: "Enoch"}]},
    {name: "Azura"}
  ]
};

階層を構築するには

js
const root = d3.hierarchy(data);

指定されたchildrenアクセサ関数は、ルートデータから始まる各データムに対して呼び出され、子を表すデータの反復可能オブジェクト(存在する場合)を返します。 childrenアクセサが指定されていない場合、デフォルトは次のようになります。

js
function children(d) {
  return d.children;
}

dataがMapの場合、暗黙的にエントリ[undefined, data]に変換され、childrenアクセサは代わりにデフォルトで次のようになります。

js
function children(d) {
  return Array.isArray(d) ? d[1] : null;
}

これにより、groupまたはrollupの結果をhierarchyに渡すことができます。

返されたルートノードと各子孫には、次のプロパティがあります。

  • node.data - hierarchyに渡された関連データ
  • node.depth - ルートの場合はゼロ、子孫の世代ごとに1ずつ増加
  • node.height - 子孫の葉からの最大距離、または葉の場合はゼロ
  • node.parent - 親ノード、またはルートノードの場合はnull
  • node.children - 子ノードの配列(存在する場合)、または葉の場合はundefined
  • node.value - ノードとその子孫のオプションの合計値

このメソッドは、ノードがinstanceof d3.hierarchyであるかどうかをテストし、ノードのプロトタイプを拡張するためにも使用できます。

node.ancestors()

ソース · このノードから始まり、各親をルートまでたどる祖先ノードの配列を返します。

node.descendants()

ソース · このノードから始まり、各子をトポロジカル順にたどる子孫ノードの配列を返します。

node.leaves()

ソース · 走査順に葉ノードの配列を返します。 は子を持たないノードです。

node.find(filter)

ソース · このノードから階層内で、指定されたフィルターが真の値を返す最初のノードを返します。そのようなノードが見つからない場合はundefinedを返します。

node.path(target)

ソース · このノードから指定されたターゲットノードまでの階層を通る最短パスを返します。パスはこのノードから始まり、このノードターゲットノードの最も近い共通祖先に上がり、次にターゲットノードに下がります。これは、階層エッジバンドリングに役立ちます。

ソース · このノードとその子孫のリンクの配列を返します。ここで、各リンクはsourceプロパティとtargetプロパティを定義するオブジェクトです。各リンクのソースは親ノードであり、ターゲットは子ノードです。

node.sum(value)

· ソース · このノードと各子孫に対してポストオーダートラバーサルで指定された関数を評価し、このノードを返します。各ノードのnode.valueプロパティは、指定された関数によって返される数値とすべての子の値の合計に設定されます。関数はノードのデータを渡され、負でない数値を返す必要があります。 _値_アクセサは、内部ノードを含む_ノード_とすべての子孫に対して評価されます。葉ノードのみに内部値を持たせたい場合は、子を持つノードに対してゼロを返します。 たとえば_node_.countの代わりに

js
root.sum((d) => d.value ? 1 : 0);

treemapなど、_node_.valueを必要とする階層レイアウトを呼び出す前に、_node_.sumまたは_node_.countを呼び出す必要があります。例えば

js
// Construct the treemap layout.
const treemap = d3.treemap();
treemap.size([width, height]);
treemap.padding(2);

// Sum and sort the data.
root.sum((d) => d.value);
root.sort((a, b) => b.height - a.height || b.value - a.value);

// Compute the treemap layout.
treemap(root);

// Retrieve all descendant nodes.
const nodes = root.descendants();

APIはメソッドチェーンをサポートしているため、次のように言うこともできます。

js
d3.treemap()
    .size([width, height])
    .padding(2)
  (root
      .sum((d) => d.value)
      .sort((a, b) => b.height - a.height || b.value - a.value))
  .descendants()

この例では、ノードデータに値フィールドがあると想定しています。

node.count()

· ソース · この *ノード*の下にある葉の数を計算し、それを *node*.valueに割り当て、同様に *ノード*のすべての子孫についても同様です。この *ノード*が葉の場合、そのカウントは1です。この *ノード*を返します。 *node*.sumも参照してください。

*node*.sort(compare)

· ソース · 指定された_compare_関数を使用して、先行順走査で、この_ノード_の子(存在する場合)と、この_ノード_の子孫の子をそれぞれソートし、この_ノード_を返します。

指定された関数には、比較する2つのノード_a_と_b_が渡されます。 _a_が_b_の前にある必要がある場合、関数はゼロ未満の値を返す必要があります。 _b_が_a_の前にある必要がある場合、関数はゼロより大きい値を返す必要があります。それ以外の場合、_a_と_b_の相対的な順序は指定されていません。詳細については、_array_.sortを参照してください。

*node*.sumとは異なり、_compare_関数には、2つのノードのデータではなく、2つのノードが渡されます。たとえば、データにvalueプロパティがある場合、円パッキングに推奨されるように、ノードとそのすべての子孫の降順の集計値でノードをソートします。

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.value - a.value);

同様に、ツリーマップアイシクルに推奨されるように、ノードを高さ(子孫の葉からの最大距離)の降順でソートし、次に値の降順でソートするには、

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.height - a.height || b.value - a.value);

ツリーデンドログラムで推奨されているように、ノードを高さの降順、IDの昇順でソートするには

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.height - a.height || d3.ascending(a.id, b.id));

新しいソート順をレイアウトに反映させたい場合は、階層レイアウトを呼び出す前に *node*.sort を呼び出す必要があります。例については、 *node*.sum を参照してください。

node[Symbol.iterator]()

ソース · *ノード*の子孫を幅優先順に反復処理するイテレータを返します。例えば

js
for (const descendant of node) {
  console.log(descendant);
}

*node*.each( *function*, *that*)

· ソース · 指定された *function* を、*ノード* とその各子孫に対して幅優先順で呼び出します。つまり、与えられた *ノード* は、深度が小さいすべてのノードと、同じ深度の先行するすべてのノードが既に訪問された場合にのみ訪問されます。指定された関数には、現在の *子孫*、ゼロベースのトラバーサル *インデックス*、およびこの *ノード* が渡されます。 *that* が指定されている場合、それはコールバックの this コンテキストになります。

*node*.eachAfter( *function*, *that*)

· ソース · 指定された *function* を、*ノード* とその各子孫に対して後順走査で呼び出します。つまり、与えられた *ノード* は、すべての子孫が既に訪問された後にのみ訪問されます。指定された関数には、現在の *子孫*、ゼロベースのトラバーサル *インデックス*、およびこの *ノード* が渡されます。 *that* が指定されている場合、それはコールバックの this コンテキストになります。

*node*.eachBefore( *function*, *that*)

· ソース · 指定された *function* を、*ノード* とその各子孫に対して先行順走査で呼び出します。つまり、与えられた *ノード* は、すべての祖先が既に訪問された後にのみ訪問されます。指定された関数には、現在の *子孫*、ゼロベースのトラバーサル *インデックス*、およびこの *ノード* が渡されます。 *that* が指定されている場合、それはコールバックの this コンテキストになります。

*node*.copy()

ソース · この *ノード* から始まるサブツリーのディープコピーを返します。(ただし、返されたディープコピーは同じデータを共有します。)返されたノードは新しいツリーのルートです。返されたノードの親は常に null で、深さは常にゼロです。