D3 기본 알아보기

시작하기

웹에서 차트를 그리기 위해서는 다양한 방법이있습니다. chartjs, vxchart 등 라이브러리가 많습니다. 그중에 기본이 되는 d3을 얕게 한번 알아보겠습니다.

선택기

1
document.querySelectorAll("pre, code");

일반적으로 자바스크립트에서 엘리먼트다수를 선택할때 사용하는 방법입니다.

1
d3.selectAll("pre, code");

d3에서 선택할때 사용하는 방법입니다.
선택값은 배열입니다.

스타일 속성주기

selectAll에 선택된 모든 엘리먼트에 속성이나 스타일을 줄 수 있습니다.

1
2
var circles = d3.selectAll("circle");
circles.attr("cx", 20).attr("cy", 20).attr("r", 20).style("fill", "red");

메소드 체이닝을 통해서 간단하게 스타일을 줄 수 있습니다.

요소 추가하기

append 메소드를 이용하면 새요소를 추가할 수 있습니다.

1
2
3
4
5
6
7
8
var body = d3.select("body");
var h1 = body.append("h1");
h1.text("Hello h1!!");

// section 각 태그들 내부에 h1을 추가합니다.
var section = d3.selectAll("section");
var h1 = section.append("h1");
h1.text("Hello section h1!");
1
2
3
4
d3.selectAll("section")
.style("backgroundColor", "red");
.append("h1");
text("Hello section h1!");

style메소드까지는 대상이 section이었습니다.
append메소드를 사용하면 새로운 h1을 대상으로 지정합니다.

데이터 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var svg = d3.select("svg");
var data = [
{ x: 110.0, y: 129.14 },
{ x: 58.0, y: 118.14 },
{ x: 113.0, y: 88.24 },
{ x: 91.0, y: 118.07 },
{ x: 181.0, y: 60.26 },
];
var circle = svg.selectAll("circle").data(data);
circle
.enter()
.append("circle")
.attr("cx", function (data) {
return data.x;
})
.attr("cy", function (data) {
return data.y;
})
.attr("r", 10)
.style("fill", "red");

데이터 객체 배열 data를 svg내부의 circle을 선택해서 enter로 넣습니다.
만약 없다면 데이터 수만큼 생성됩니다.
append로 내부에 circle을 추가합니다. 속성으로 데이터 값의 x, y를 사용합니다.

결과물

기존에 요소가 없는 새로운데이터를 입력시

1
2
3
4
5
6
7
8
9
10
11
12
var circle = svg
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", function (data) {
return data.x;
})
.attr("cy", function (data) {
return data.y;
})
.attr("r", 2.5);

기존 요소에 결합한 새 데이터

1
2
3
4
5
6
7
8
9
10
var circle = svg
.selectAll("circle")
.data(data)
.attr("cx", function (data) {
return data.x;
})
.attr("cy", function (data) {
return data.y;
})
.attr("r", 2.5);

키 기능

join을 제어할 수 있습니다.
기본적으로 join은 index입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var svg = d3.select("svg");
var data = [
{ name: "Alice", x: 110.0, y: 129.14 },
{ name: "Bob", x: 58.0, y: 118.14 },
{ name: "Carol", x: 113.0, y: 88.24 },
{ name: "Dave", x: 91.0, y: 118.07 },
{ name: "Edith", x: 181.0, y: 60.26 },
];
function key(d) {
return d.name;
}
var circle = svg
.selectAll("circle")
.data(data, key)
.enter()
.append("circle")
.attr("cx", function (data) {
console.log(data);
return data.x;
})
.attr("cy", function (data) {
return data.y;
})
.attr("r", 10)
.style("fill", "red");

키 함수는 각 데이터에 대해 고유 한 문자열을 반환합니다.
자세한 사항은 Thinking with joins에서 확인할 수 있습니다.

데이터 로딩

stock.json
1
2
3
4
5
6
7
8
9
10
[
{ "symbol": "S&P 500", "date": "Jan 2000", "price": 1394.46 },
{ "symbol": "S&P 500", "date": "Feb 2000", "price": 1366.42 },
{ "symbol": "S&P 500", "date": "Mar 2000", "price": 1498.58 },
{ "symbol": "S&P 500", "date": "Apr 2000", "price": 1452.43 },
{ "symbol": "S&P 500", "date": "May 2000", "price": 1420.6 },
{ "symbol": "S&P 500", "date": "Jun 2000", "price": 1454.6 },
{ "symbol": "S&P 500", "date": "Jul 2000", "price": 1430.83 },
{ "symbol": "S&P 500", "date": "Aug 2000", "price": 1517.68 }
]
1
2
3
4
5
6
var format = d3.time.format("%b %Y");
d3.json("./stocks.json", function (stocks) {
stocks.forEach(function (d) {
d.date = format.parse(d.date);
});
});

날짜구문을 분석해서 변환해야 합니다.

Scales과 Axes

속성 및 스타일은 위치와 모양을 제어한다.
scale은 데이터 공간에서 시각적인 공간으로 매핑되는 함수이다.

1
2
3
var x = d3.scaleLinear().domain([10, 20]).range([0, 700]);

x(16); // 240

위의 코드를 보자면 선형 스케일은 단순히 변환합니다.
스케일의 도메인은 예상되는 데이터 값(예시로 10 ~ 20)이며 원하는 출력값입니다.
0은 차트 왼쪽이고 700은 찬트의 오른쪽입니다.

d3.scaleSqrt
d3.scaleLog
sqrt (또는 pow) 스케일은 지수 변환을 적용합니다.
log 스케일은 로그 변환을 적용합니다.

Domains과 Ranges

1
2
3
var x = d3.scaleLinear()
.domain([0, d3.max(numbers)])
.range([0, 700]);

d3.mind3.max도메인을 계산합니다.

1
2
3
4
5
6
7
8
var x = d3.scaleLog().domain(d3.extent(numbers)).range([0, 700]);

function value(d) {
return d.value;
}
var x = d3.scaleLog()
.domain(d3.extent(objects, value)) // 원하는 경우 array.map을 사용할 수 있습니다.
.range([0, 720]);

d3.extent는 최소값과 최대값을 동시에 계산합니다.

Interpolators

1
2
3
4
5
var x = d3.scaleLinear().domain([12, 24]).range(["steelblue", "brown"]);
x(16); // #666586

var x = d3.scaleLinear().domain([12, 24]).range(["0px", "720px"]);
x(16); // 240px

RGB 보간을 위해 색상이 자동으로 감지됩니다.
문자열 보간은 포함 된 숫자와 일치합니다. 매우 유연합니다.

1
2
3
4
5
6
var x = d3.scaleLinear()
.domain([12, 24])
.range(["steelblue", "brown"])
.interpolate(d3.interpolateHsl);

x(16); // #3cb05f

원하는 경우 보간기를 명시 적으로 설정할 수 있습니다.

Ordinal Scales

1
2
3
4
5
6
var x = d3.scaleOrdinal()
.domain(["A", "B", "C", "D"])
.rangeRoundBands([0, 720], 0.2);

x("B"); // 206, bar position
x.rangeBand(); // 137, bar width

여기서 scale은 막대의 왼쪽 위치를 반환하는 반면 rangeBand 메서드는 막대 너비를 반환합니다. rangeBands (여기서 .2)에 대한 두 번째 인수는 막대 사이에 예약 할 패딩의 양입니다.

rangeRoundBands 메서드는 앤티 앨리어싱이 모호해지지 않도록 전체 픽셀로 반올림한다는 점을 제외하고 rangeBands와 동일합니다.

Axes

1
2
// var yAxis = d3.svg.axis().scale(y).orient("left");
var yAxis = d3.axisLeft().scale(y);

주어진 스케일에 대한 축을 생성하고 원하는대로 구성합니다.

1
svg.append("g").attr("class", "y axis").call(yAxis);

선택을 호출하여 축을 렌더링합니다.

Ticks

사람이 읽을 수있도록 값에 대해 정량적 척도를 작성 할 수 ​​있습니다.

1
2
var x = d3.scaleLinear().domain([12, 24]).range([0, 700]);
x.ticks(5); // [12, 14, 16, 18, 20, 22, 24]

Svg 좌표

좌표
transforms를 이용해서 origin의 위치를 정의할 수 있다.

1
2
3
4
5
6
7
8
9
var svg = d3
.select("body")
.append("svg")
.attr("width", outerWidth)
.attr("height", outerHeight);

var g = svg
.append("g")
.attr("transform", "translate(" + marginLeft + "," + marginTop + ")");

Svg 기본

svg에서 사용하는 요소들 입니다.

1
2
3
4
5
<rect x="0" y="0" width="0" height="0" rx="0" ry="0"> // 사각형
<circle cx="0" cy="0" r="0"> // 원
<line x1="0" y1="0" x2="0" y2="0"> // 선
<text x="0" y="0" dx="0" dy="0" text-anchor="start"> // 텍스트 본문
<path d="M152.64962091501462,320.5600780855698L133.88913955606318,325.4363177123538L134.96890954443046,330.37917634921996L131.19348249532786,331.158393614812L98.56681109628815,335.53933807857004L91.14450799488135,333.796620..."> // 경로

path에서는 다른 숫자로된 언어가 필요합니다.

Path Generator

d3.line

x와 y로 경로를 정의할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
var x = d3.scaleLinear(),
y = d3.scaleLinear();

var line = d3.line()
.x(function (d) {
return x(d.x);
})
.y(function (d) {
return y(d.y);
});

svg.append("path").datum(objects).attr("class", "line").attr("d", line);

데이터 접근 자로 스케일을 구성하여 위치를 정의합니다.
데이터를 직접 라인 생성기로 전달하거나 selection.attr을 통해 전달해야 합니다.

d3.svg.area

x, y0 및 y1로 경로를 정의할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
var x = d3.scaleLinear(),
y = d3.scaleLinear();

var area = d3.svg
.area()
.x(function (d) {
return x(d.x);
})
.y0(height)
.y1(function (d) {
return y(d.y);
});

스택되지 않은 영역 차트의 경우 y0는 일정합니다.

Radial Areas & Lines

d3.arc

파이 및 도넛형 차트의 경로생성기입니다.

1
2
3
4
5
6
7
var myArc = {
innerRadius: 0,
outerRadius: 360,
startAngle: 0, // 12 o'clock
endAngle: 1.2, // radians
};
var arc = d3.arc().innerRadius(0).outerRadius(360);

기본적으로 호 관련 속성이있는 객체를 입력으로 사용합니다.

d3.pie

1
2
// pie의 기본레이아웃
var pie = d3.pie();

d3.pie를 사용하여 데이터에서 시작 및 끝 각도를 계산할 수 있습니다..

Layouts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
d3.treemap;
d3.tree;
d3.pack;
d3.partition;
d3.force;
d3.bundle;
d3.voronoi;
d3.chord;

var treemap = d3.treemap().padding(4).size([width, height]);

function x(d) {
return d.x;
}
function y(d) {
return d.y;
}
function dx(d) {
return d.dx;
}
function dy(d) {
return d.dy;
}

svg
.selectAll(".cell")
.data(treemap.nodes(root))
.enter()
.append("rect")
.attr("class", "cell")
.attr("x", x)
.attr("y", y)
.attr("width", dx)
.attr("height", dy);

계층적 레이아웃은 데이터의 공유 표현을 사용합니다.

1
2
var parent = {"children": […]},
child = {"value": …};

마지막으로

d3 기본이 다져진다면 아무리 어려운 그래프라도 처음에는 어렵겠지만, 차근차근 하다보면 충분히 만들수 있습니다.
D3.js 창시자인 엠보스톡의 워크샵을 참고했습니다.

Share