본문 바로가기

Javascript/Node.js

D3.js 사용법을 알기 위한 튜토리얼 예제 분석(D3공식홈페이지 example과 실시간 Line 그래프 예제 분석)

반응형

D3.js 기본 문법 정리

D3.js는 Data-Driven Documents의 약어로 데이터를 렌더링할 수 있는(그릴 수 있는, 다룰수 있는) 웹 기반 문서 라이브러리다.

좀 더 간단 명료하게 설명하면 데이터 시각화 라이브러리다. (실시간 데이터 차트 및 다양한 그래프)

D3 공식홈페이지에 가보면 엄청나게 다양한 그래프들이 있고 거기서 원하는 것을 골라서 소스를 얻어갈 수 있다.

라이센스도 BSD로 영리든 비영리든 마음대로 사용, 수정해도 된다.

D3.js의 기본 문법(사용법)을 숙지하고 예제코드를 분석할 것이다.


- D3 작업 순서

1. 데이터를 불러온다.

2. 작업할 공간을 선택한다.

3. 공간에 불러온 데이터를 연결(바인딩)한다.

4. 각각 연결한 것을 원하는대로 그린다.

1
2
3
4
5
6
7
var dataset = [ 155322021 ];
d3.select("body")          // 1
  .selectAll("p")          // 2
  .data(dataset)           // 3
  .enter()                 // 4
  .append("p")             // 5
  .text("hi jeongpro!");   // 6


위 코드는 아주 간단한 D3 코드다. (d3를 이용하려면 d3.js 파일이나 cdn으로 한 줄만 가져오면 됨 위에선 생략)

첫 번째줄에서는 데이터 배열을 불러왔다. (데이터 불러오기)

csv, tsv, json등의 파일에서 데이터를 불러올 수도 있고 서버에서 데이터를 response 받을 수도 있다.

어떤 방법으로든 데이터를 불러온다.

(1) d3.select("body") 로 <body>태그를 선택했다. (jquery selector랑 비슷하네? 하지만 차이점은 아래에서 설명..)

(2) .selectAll("p") 로 위에서 선택한 <body>태그 자식 노드로 있는 모든 <p>태그를 선택했다. (공간 선택하기)

jquery에서 사용하던 선택자와 비슷해보여서 익숙하지만 아주 명확한 차이점이 있다.

jquery에서는 이미 존재하는 태그를 선택해야하지만 d3에서는 존재하지 않는 태그를 선택해야한다.

무슨말인지는 아래에서 바인딩을 보면 알 수 있다.

(3) .data(dataset) 으로 데이터를 불러와 바인딩한다.

(4) .enter() 를 통해 바인드가 되지않은 <p>요소에 데이터를 넣어 새로운 selection을 반환한다.

아까 선택하기에서 존재하지 않는 태그를 선택해야된다고 한 이유가 여기에 있다.

만약 <body>태그 안에 2개의 <p>태그가 존재했다면 그 2개의 p태그에는 데이터 바인딩이 적용되지 않고 3개의 p태그를 새로 만들어 데이터를 바인딩했을 것이다. (3개는 위에서 데이터배열의 수가 5개이기 때문 5-2=3)

<출처 : https://www.slideshare.net/aliceinwoon/d3js-2 >

(5) .append("p") 를 통해 해당 데이터 공간 수 만큼 문서요소를 만든다.

(6) .text("hi jeongpro!"); 로 해당 p 태그들에 text를 삽입한다.

<body에 p태그가 2개가 있을 때 결과>

1
2
3
4
5
p태그 내용1
p태그 내용2
hi jeongpro!
hi jeongpro!
hi jeongpro!


<body에 p태그가 없을 때 결과>

1
2
3
4
5
hi jeongpro!
hi jeongpro!
hi jeongpro!
hi jeongpro!
hi jeongpro!



* 위에서 의문이 들었을 수 있다. 없는 공간을 선택한다고 하면 .selectAll("div")로 해도 되고 .selectAll("jeongpro")라고 해도 되지않을까? 맞다. 이렇게 해도 동일하게 빈 selection들을 반환한다. (div, jeongpro 태그가 없다면)

D3 공식홈페이지 예제 소스 분석

기본 문법을 알았보았으니 쉬운 예제소스를 분석해보고 실행해본다.

아까 말했듯이 d3 공식홈페이지에서 이미 충분한 그래프 유형과 소스를 제공하고 있다. 열어서 분석하고 사용하면 끝이다. (basic chart인 line chart를 선택했다.)

data.tsv

- 참고로 tsv는 csv가 콤마로 데이터를 구분하는 것처럼 tab으로 데이터를 구분하는 데이터형식이다.

이런 데이터가 엄청나게 존재한다. 링크(https://bl.ocks.org/mbostock/3883245)

[index.html 소스]

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<svg width="960" height="500"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
 
var svg = d3.select("svg"), // svg태그 선택
    margin = {top: 20, right: 20, bottom: 30, left: 50},// 그래프에서 margin을 정함
    width = +svg.attr("width"- margin.left - margin.right, // 전체 width에서 양쪽 마진 제외
    height = +svg.attr("height"- margin.top - margin.bottom,// 전체 heigth에서 위아래로 마진 제외
    g = svg.append("g").attr("transform""translate(" + margin.left + "," + margin.top + ")");
    //svg에 <g>태그를 넣고 속성을 넣음 <g transform="translate(50,20)">
var parseTime = d3.timeParse("%d-%b-%y");
//시간 파싱 함수
var x = d3.scaleTime()
    .rangeRound([0, width]);
//x축은 시간값 범위 0~width
var y = d3.scaleLinear()
    .rangeRound([height, 0]);
//y축은 linear 순차적인 값, 범위 height~0
//y축은 좌상단이 (0,0)이고 y값이 증가할수록 밑으로 내려가도록 그리기때문
var line = d3.line()
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.close); });
//d3.line()으로 선을 그리는데 x값은 콜백으로 x(데이터.date값), y값은 y(데이터.close값)
//d3.tsv로 tsv파일을 읽을 수 있음
d3.tsv("data.tsv"function(d) {
  d.date = parseTime(d.date);
  d.close = +d.close;
  return d;
}, function(error, data) {
  if (error) throw error;
//d3.extent는 [최소,최대] 시작과 끝 직선 어디만큼 그릴지를 리턴
//domain은 입력 값의 구간, range는 출력 값의 범위
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain(d3.extent(data, function(d) { return d.close; }));
 
//aixs는 x축선과 y축선을 그리기위한 용도다.
//x축
  g.append("g")
      .attr("transform""translate(0," + height + ")")
      .call(d3.axisBottom(x))
    .select(".domain")
      .remove();
//y축
  g.append("g")
      .call(d3.axisLeft(y))
    .append("text")
      .attr("fill""#000")
      .attr("transform""rotate(-90)")
      .attr("y"6)
      .attr("dy""0.71em")
      .attr("text-anchor""end")
      .text("Price ($)");
//데이터선
  g.append("path")
      .datum(data)
      .attr("fill""none")
      .attr("stroke""steelblue")
      .attr("stroke-linejoin""round")
      .attr("stroke-linecap""round")
      .attr("stroke-width"1.5)
      .attr("d", line);
});
 
</script>
cs

주석을 달아보았으나 명쾌하게 해설하지 못했다. 이부분을 좀 더 공부해서 수정할 예정이다.


D3 실시간 그래프(Realtime streaming)

실시간 그래프를 그리는 간단한 예제도 넣어놓고 분석해보면 좋을듯 하다.

[index.html]

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
<!DOCTYPE html>
<html lang="en" >
<head>
  <meta charset="UTF-8">
  <title>D3 REaltime chart </title>
<style>
    svg {
      font: 10px sans-serif;
    }
    .line {
      fill: none;
      stroke: #000;
      stroke-width: 1.5px;
    }
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
</style>
</head>
<body>
    <script src='https://d3js.org/d3.v3.min.js'></script>
    <script  src="js/index.js"></script>
</body>
</html>
 


[js/index.js]

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
var n = 40,
    random = d3.random.normal(0, .2),
    data = d3.range(n).map(random);
 
var margin = {top: 20, right: 20, bottom: 20, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;
 
var x = d3.scale.linear()
    .domain([0, n - 1])
    .range([0width]);
 
var y = d3.scale.linear()
    .domain([-11])
    .range([height0]);
 
var line = d3.svg.line()
    .x(function(d, i) { return x(i); })
    .y(function(d, i) { return y(d); });
 
var svg = d3.select("body").append("svg")
    .attr("width"width + margin.left + margin.right)
    .attr("height"height + margin.top + margin.bottom)
  .append("g")
    .attr("transform""translate(" + margin.left + "," + margin.top + ")");
 
svg.append("defs").append("clipPath")
    .attr("id""clip")
  .append("rect")
    .attr("width"width)
    .attr("height"height);
 
svg.append("g")
    .attr("class""x axis")
    .attr("transform""translate(0," + y(0+ ")")
    .call(d3.svg.axis().scale(x).orient("bottom"));
 
svg.append("g")
    .attr("class""y axis")
    .call(d3.svg.axis().scale(y).orient("left"));
 
var path = svg.append("g")
    .attr("clip-path""url(#clip)")
  .append("path")
    .datum(data)
    .attr("class""line")
    .attr("d", line);
 
tick();
 
function tick() {
 
  // push a new data point onto the back
  data.push(random());
 
  // redraw the line, and slide it to the left
  path
      .attr("d", line)
      .attr("transform"null)
    .transition()
      .duration(500)
      .ease("linear")
      .attr("transform""translate(" + x(-1+ ",0)")
      .each("end", tick);
 
  // pop the old data point off the front
  data.shift();
 
}
cs

참고 사이트

https://d3js.org/

http://blog.nacyot.com/articles/2015-02-02-d3-selection/

반응형
  • Yoon BS 2018.04.17 11:06

    안그래도 요즘 CSV파일과 대량의 로그를 가지고 비교 분석할게 있었는데 같이 연동하면 참 좋겠네요

    • Favicon of https://jeong-pro.tistory.com BlogIcon JEONG_AMATEUR 2018.04.17 14:27 신고

      그래프를 그리고, 에러 로그가 남았을 때 에러가 나기 전 특정 시점부터 그래프에서 패턴을 찾을 수 있으면 참 좋겠네요

  • BlogIcon Greg 2018.06.09 21:37

    씨투아이 차트 데모도 d3로 만들었네요.
    www.B2i-lab.com

  • localcityz 2018.06.10 15:28

    생활코딩보다가 자료 수집차 검색해서 왔다는건 거짓말이구요 초대장이 받고 싶어서 왔습니다
    남는 초대장 있으시면 보내주시면 감사하겠습니다 티스토리 블로그 운영이 하고 싶습니다
    제 메일주소는 localcityz@gmail.com 입니다
    감사합니다

  • 근둥 2018.10.12 18:21

    c3.js나 chart.js 쓰다가 이번에 d3.js를 쓸 일이 생겼는데 조금 복잡하더라구요.. 이 글 보고나니 어느정도 정리가 된 것 같습니다. 감사합니다

  • 익명 2019.02.12 17:45

    비밀댓글입니다

    • Favicon of https://jeong-pro.tistory.com BlogIcon JEONG_AMATEUR 2019.02.12 19:43 신고

      크롬에서 그래프가 보이지 않은 이유는 cdn으로 d3를 가져오는 것이 보안에 막히기 때문이랍니다.
      <script src="https://d3js.org/d3.v4.min.js"></script>
      위와 같은 형식으로 가져오지 마시고 직접 다운로드한다음에 링크하시기 바랍니다.

  • tutorial 2020.04.10 11:11

    d3 공식문서에서 예제를 봐도 잘모르겠네요. chart{} <- 이런식으로 묶여있고 전체코드가 아니라 전부 분해되있다보니 예제코드를 복붙해서 파악하기가 힘든데 어떤식으로 봐야되나요 ?

    • Favicon of https://jeong-pro.tistory.com BlogIcon JEONG_AMATEUR 2020.04.11 20:43 신고

      솔직히 D3에서 제공하는 예제 소스를 이해하기 어렵습니다.

      그나마 소스가 짧은 (line같은) 차트들을 분석해보시고 점진적으로 화려한(?) 차트를 보면서 API를 학습하는게 요령이지 않을까 합니다...

      원하는 차트를 예제만 놓고 분석하려고하면 진짜 어렵더라고요...