블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2015. 8. 20. 18:05 Data Visualization/D3.js

올 하반기는 D3.js를 이용한 차트 라이브러리 만들기를 주된 작업으로 잡고 있다. 데이터 시각화를 위해 SVG를 자유자재로 다루기 위해 D3.js를 심도있게 이해하는 것이 어느 때보다 필요하기 때문이다. AngularJS/React/Meteor 는 데이터 시각화 서비스를 개발하기 위한 기술로 익히고 있다. 마이크 보스톡의 튜토리얼 레퍼런스에 나온 내용중 좋은 기사를 실습 요약한다. 





준비하기 

  

테스트를 위해 로컬에서 하지 않고 JSBin 서비스를 이용한다. GitHub 계정으로 로그인을 하고 자신이 원하는 테마(Theme)를 아래와 같이 설정할 수 있다. Monokai와 Sublime 키바인딩, FontSize 11로 설정을 했다. "Add library"에서 "D3 3.x" 를 선택하면 HTML에 자동으로 추가된다. 





엘러먼트 선택


D3는 jQuery의 Selector 처럼 Selection(셀렉션)을 통해 문서를 접근할 수 있다. 그리고 선택된 셀랙션에 대해 메소드 체이닝(Chaining Methods)를 통해 제어를 할 수 있다. 체이닝의 이점은 var 를 사용하지 않아도 되고 코드를 간결하게 유지할 수 있다. 

Let's Make Bar Chart on jsbin.com





차트 만들기 


HTML로 직접 바차트를 만들 수 있지만 D3를 이용해 어떻게 만드는지 보자. 

JS Bin on jsbin.com


코드의 순서는 다음과 같다. 

- var chart  = d3.select('.chart') : selector를 이용해서 Chart container를 선택한다. 

- var bar = chart.selectAll('div') : 데이터 조인 (data join)을 위해 셀랙션(selection)을 초기화 한다. 데이터 조인은 데이터 변경에 따라 엘러먼트를 생성, 업데이트, 삭제할 수 있는 것이다. (자세한 사항은 "Thinking with joins"를 참조한다)

- var barUpdate = bar.data(data) : selection.data를 통해 데이터를 셀랙션과 조인(join)한다. 

- var barEnter = barUpdate.enter().append('div') : 'div' 태그가 .chart 안에 존재하지 않기 때문에 barUpdate는 일어나지 않는다. 없을 경우 새로운 데이터에 대한 임의위치(placeholder)를 만들어 주기 위해 enter()를 호출한 후, 임의위치에 append('div')를 통해 div 태그를 신규 생성한다. 

- barEnter.style('width', ....) : 신규 생성된 div에 대한 스타일을 설정한다. D3에서는 attr(), style(), property()를 통해 엘러먼트를 설정할 수 있다. 

- barEnter.text(...) : 레이블을 설정한다. 





스케일 맞추기 


위의 소스를 보면 width에 대해 10 상수값이 쓰였다. 실제값을 정의역값이라하고 domain(도메인)이라하며, 10을 곱하여 나온 변경된 값을 치역(range)값이라 한다. 수치에 대한 일정한 스케일(Scale)을 만들어 주는 기능이 D3에서는 linear scale 이다. x에 대한 스케일을 만들어 보자.

JS Bin on jsbin.com





SVG를 사용해 만들기 


위에 소스는 HTML을 통해 만들었지만 SVG(Scalable Vector Graphics)를 이용해 표현해 보도록 한다. SVG를 사용하면 네이티브 레벨에서 다양한 모양을 만들어 낼 수 있다. HTML에 <!DOCTYPE html> 태그를 최상단에 넣어주고 사용할 수 있다. SVG는 HTML의 일반 스타일이 아닌 다른 스타일 명을 쓴다. 예로 background-color는 fill로 쓴다. SVG 프로퍼티 스펙을 참조한다. 좌표는 top-left 코너에서 시작한다. SVG로만 차트를 표현한 예이다. 

JS Bin on jsbin.com


- transform을 이용해 크기의 절대좌표값으로 translate(x, y)를 통해 이동을 하고 있다. 

- g 그룹 논리 태그를 통해 하위에 SVG rect으로 사각형을 표현한다. 

- text 태그를 통해 레이블을 설정한다. 


D3를 이용해 다시 표현해 보자. g 셀랙션은 data 배열 6개 만큼이 생성되어 rect과 text 태그를 통해 바차트를 그린다. 

JS Bin on jsbin.com


- x 스케일을 만든다 

- svg 의 크기를 결정한다 

- svg안에 g가 들어가므로 enter selection을 통해 추가하고 transform으로 g 위치를 옮긴다. 

- var bar 값은 data 값 수 만큼의 g 배열을 리턴 받아 rect과 text를 설정한다. rect과 text는 g로 부터 data 값을 받아 사용한다. 





데이터를 불러와서 차트그리기


D3는 TSV(Tab-seperated values)나 CSV(Comma-seperated values)로 파일 형식을 읽어와서 JSON으로 변환해 사용할 수 있다. d3.csv API를 참조한다. 테스트를 위해서 GitHub에 별도 저장소를 하나 만들고 data.tsv 파일을 하나 만든다. (탭으로 구분)

name value

Locke 4

Reyes 8

Ford 15

Jarrah 16

Shephard 23

Kwon 42


GitHub에 파일을 만들고 파일을 선택하고 "Raw" 버튼을 클릭하면 상단에 접근 주소가 나온다. 

예) https://raw.githubusercontent.com/mobiconsoft/d3_practice/master/data.tsv

사용할 Raw Data 주소이다. 


JSBin에서 TSV 파일을 호출해 보자. 

JS Bin on jsbin.com


- 데이터의 갯수를 모르기 때문에 호출후 x.domain 정의역 값을 설정한다. 

- 데이터는 [{name: 'Locke', value: 4}, ....] 와 같이 데이터가 오브젝트이므로 function(d) { return d.value; } 값을 사용한다. 

- tsv 호출시 값에 대한 컨버젼을 하지 않고 전부 string으로 취급하므로 type 펑션은 숫자로 변환하는 유틸이다. 





컬럼 차트로 전환하기 


수평 바차트를 수직 컬럼 차트로 변환해 보자. X축은 이름을 표현하고 Y축은 값을 표현할 것이다. X축과 같이 문자 알파벳으로 표현될 경우는 Ordinal 스케일을 사용해야 하고 치역의 값을 수량적으로 할 수 없기 때문에 자동으로 맞춰주는 rangeBands 또는 rangePoints 를 사용한다. rangeBands/Points는 각 시리즈의 넓이를 의미하고 시르즈(바)간의 padding을 지정해 주고 싶다면 rangeRoundBands를 통해 파라미터를 설정할 수 있다. 

JS Bin on jsbin.com


- X축은 이름이기 때문에 Ordinal 스케일이다. 

- bar의 X 스케일 만큼 이동하고, rect의 y점을 지정 후 그린다.

- x.rangeBand()는 바의 넓이를 자동으로 계산해 넘겨준다. 





축 추가하기 


컬럼 차트만 그려지니 썰렁하다. 축을 그려보자. D3는 축을 만들 수 있도록 d3.svg.axis() API를 제공하고, 축의 방향을 설정한 후 기존에 생성한 x, y Scale을 설정한다. 축에 스케일 설정을 하고 SVG의 g 그룹에 축을 설정할 때는 selection.call API를 사용한다. 축을 설정하면 <g class="y axis"> 또는 <g class="x axis"> 클래스가 자동 설정된다. 해당 값은 사용자가 아래와 같이 수정할 수 있다. 

<style>

.bar {

  fill: steelblue;

}


.axis text {

  font: 10px sans-serif;

}


.axis path,

.axis line {

  fill: none;

  stroke: #000;

  shape-rendering: crispEdges;

}


.x.axis path {

  display: none;

}

</style>


JSBin 코드를 보자.

JS Bin on jsbin.com


- SVG 넓이 안에 들어가는 차트를 위한 마진을 설정한다. 

- x, y 스케일을 구한다. 

- x, y 축을 스케일을 적용해 구한다. 

- 차트 영역을 설정하고 차트 셀랙션을 생성한다 

- 데이터가 들어오면 x, y 스케일에 대한 정의역(domain)값을 설정한다. 

- x, y 스케일에 대한 정의역 값이 설정된 후에야 차트 g 그룹에 x, y Axis를 설정할 수 있다. 정의역값이 설정되기 전에 축 설정이 되면 축의 Tick 값이 표현되지 않는다. 

- .bar 클래스를 선택하고 데이터를 조인하면 임의영역(placeholder)가 생성되고, 여기에 rect을 append하여 컬럼을 기존처럼 그린다.  




<참조>


- 원문 : Let's Make a Bar Chart  (보스톡의 소스)   

- SVG 스펙


posted by 윤영식