d3 라이브러리의 Hierarchy 메서드는 계층구조를 만들어 주는 역할을 합니다.

계층 구조를 만들기 위해서는 루트 노드가 필요합니다. 만일 이미 데이터가 JSON 처럼 계층 구조으로 만들어져 있다면, 바로 d3.hierarchy를 사용할 수 있습니다. 만일 CSV(comma-separated values)와 같은 표 형식의 데이터로 만들어져 있다면 d3.stratify를 사용하여 계층 구조로 재정렬 할 수 있습니다.

d3.hierarchy(data[, children])

지정된 계층 데이터로부터 루트 노드를 구축합니다. 데이터는 루트 노드를 나타내는 객체 여야합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"name": "Eve",
"children": [
{"name": "Cain"},
{
"name": "Seth",
"children": [{"name": "Enos"},{"name": "Noam"}]
},
{"name": "Abel"},
{
"name": "Awan",
"children": [{"name": "Enoch"}]
},
{"name": "Azura"}
]
}

지정된 자식 접근자 함수는 루트 데이터로부터 시작되는 각데이터에 대해 호출됩니다. 그리고 자식을 나타내는 데이터 배열이나, 현재 데이터에 자식이 없다면 null을 반환해야 합니다. 자식을 지정하지 않으면 기본값은 다음과 같습니다.

1
2
3
function children(d) {
return d.children;
}

리턴되는 노드와 각 자손은 다음과 같은 속성을 가지고 있습니다.

  • node.data - 관련 지을 수 있었던 데이터.
  • node.depth - 루트 노드는 0이고 각 자손 생성마다 하나씩 증가합니다.
  • node.height - 마지막(leaf) 노드의 경우 0이고, 내부 노드라면 하위 마지막 노드 까지의 거리입니다.
  • node.parent - 부모 노드이고, 루트 노드의 경우 null입니다.
  • node.children - 자식노드 배열입입니다. 마지막 노드의 경우 undefined입니다.
  • node.value - 노드와 그 자손의 합계 된 값입니다. 선택 사항입니다.

이 메소드는 노드가 d3.hierarchy의 인스턴스인지 테스트하고 노드 prototype을 확장하는 데에도 사용할 수 있습니다.

node.ancestors()

현재 노드를 포함해서, 루트 노드까지의 상위 노드들을 배열로 반환합니다.

node.descendants()

현재 노드를 포함해서, 루트 노드까지의 하위 노드들을 배열로 반환합니다.

node.leaves()

횡단 순서로 leaf 노드를 배열로 반환합니다. (leaf 노드는 자식이 없는 마지막 요소입니다.)

node.path(target)

node로부터 지정된 target 노드까지의 계층을 통과하는 최단 경로를 리턴합니다. 경로는 이 노드에서 시작하여 이 노드와 target 노드의 가장 가까운 상위 노드로 상승한 다음 대상 노드로 내립니다. 이것은 계층적 엣지 번들링에 특히 유용합니다.

node의 링크들을 배열로 반환합니다. 링크들은 sourcetarget 요소를 정의하는 객체입니다. 각 링크의 source는 부모 노드이며 target은 자식 노드입니다.

node.sum(value: function)

노드와 각 자손들에 대해 post-order traversal방식으로 지정된 함수의 리턴값을 측정하고, 이 노드를 리턴합니다.
각 노드의 node.value요소는 지정된 함수가 리턴 한 숫자 value와, 모든 자손의 결합 된 value를 더한 값으로 설정됩니다.
함수는 노드의 데이터를 넘겨 받고, non-negative number를 반환해야 합니다.
value 접근자는 노드와 안쪽 노드들을 포함함 모든 자손들을 측정합니다.

만일 마지막 노드의 내부 값만 원한다면, 자식이 있는 노드에 대해서 0을 리턴하면 됩니다.
예를들어 node.count 대신에…

1
root.sum(function(d) { return d.children ? 0 : 1; });

node.value가 필요한 hierarchical 레이아웃(d3.treemap 등…)을 호출하기 전에는 반드시 node.sum 또는 node.count를 호출해야 합니다. 그다음에 모든 자손 노드들의 배열을 만들어야 합니다.

1
2
3
4
5
6
7
8
var treemap = d3.treemap()
.size([width, height])
.padding(2);
var nodes = treemap(root
.sum(function(d) { return d.value; })
.sort(function(a, b) { return b.height - a.height || b.value - a.value; }))
.descendants();

위 예제는 노드 데이타가 value를 가지고 있다고 가정합니다.

node.count()

자신을 포함한 모든 자손요소에 대해서 자식노드의 수를 계산하고, 이를 node.value에 할당합니다. 만일 마지막 노드라면, count는 1입니다.

node.sort(compare)

지정된 compare 함수를 사용하여 pre-order traversal 방식으로 현재 노드의 자식 노드와 현재 노드의 자손 자식들을 각각 정렬하고 현재 노드를 반환합니다. compare함수는 비교하기 위한 노드 두개(a, b)를 인자로 받습니다. 만일 a가 b앞에 위치해야 한다면, 함수는 반드시 0보다 작은 수를 반환해야 한다. 만일 b가 앞에 위치해야 한다면 함수는 0보다 큰수를 반환해야 한다. 그렇지 않으면 a와 b의 순서가 지정되지 않습니다. Array의 sort매소드 참고

node.sum과는 다르게, compare함수는 2개의 노드 데이터가 아닌, 2개의 노드를 인자로 받습니다. 예를들어 만일 datavalue 프로퍼티를 가지고 있다면,
예를 들어, datavalue 프로퍼티이 있으면 circle-packing에서 권장되는 것처럼 노드와 그 하위 노드의 내림차순 집계 값별로 노드를 정렬합니다.

1
2
3
root
.sum(function(d) { return d.value; }) //data.value
.sort(function(a, b) { return b.value - a.value; }); //node.value

비슷하게, treemapsicicles에 권장되는 높이(마지막 노드에서 가장 큰 거리)를 내림차순으로 노드를 정렬 한 다음 내림차순으로 정렬하려면 다음을 수행합니다.

1
2
3
root
.sum(function(d) { return d.value; })
.sort(function(a, b) { return b.height - a.height || b.value - a.value; });

trees and dendrograms에 권장되는 것처럼 높이를 내림차순으로 정렬하고 노드를 오름차순으로 정렬하려면 :

1
2
3
root
.sum(function(d) { return d.value; })
.sort(function(a, b) { return b.height - a.height || a.id.localeCompare(b.id); });

만일 레이아웃을 새롭게 정렬하기 윈한다면, 계층적인 레이아웃을 실행하기전에 반드시 node.sort를 호출해야 합니다.

node.each(function)

해당 노드와 각각의 자손노드를 breadth-first order 기준으로 순회하면서 지정된 함수를 실행합니다. 함수에는 현재 node가 인자로 전달됩니다.

node.eachAfter(function)

주어진 노드가 모든 자손이 이미 방문 된 후에 만 방문하도록 pre-order traversal방식으로 순회하면서 지정된 함수를 호출합니다. 마찬가지로 지정된 함수가 현재 노드에 전달됩니다.
Invokes the specified function for node and each descendant in post-order traversal, such that a given node is only visited after all of its descendants have already been visited. The specified function is passed the current node.

node.eachBefore(function)

pre-order traversal방식으로 순회하면서 지정된 함수를 호출하여, 주어진 노드가 모든 조상이 이미 방문 된 후에 만 방문하도록 합니다. 지정된 함수가 현재 노드에 전달됩니다.

node.copy()

해당 노드로부터 시작하여 하위요소들의 깊은복사(deep cody)본을 반환합니다.(하지만 리턴되는 복사본은 같은 데이터를 참조합니다.)
반환 된 노드는 새 트리의 루트입니다. 당연하겠지만, 반환된 노드의 부모는 항상 null이며 깊이는 항상 0입니다.

참조

API Reference