D3js 인액션
1. D3js란?
D3js는 브라우저에 그래픽 요소에 다른 라이브러리보다 더 저수준의 접근을 제공하므로, 유연하고 자유롭게 그래픽요소를 이용하게 해준다.
차트는 물론 표 리스트 html 형태도 처리할수 있다.
범용 라이브러리로는 할수없는 고유한 기능도 구현 가능하다.
D3js는 셀력션과 바인딩이다.
D3js의 강점은 데이터와 웹요소를 손쉽게 결합하는 셀렉션 기능이다.
셀렉터는 브라우저 dom api의 쿼리셀렉터와 비슷.
.data([1,2 3]) 와 같이.선택된 요소에 데이터 바인딩이 가능하다.
DOM은 z-index로 요소를 앞뒤로 그릴수 있다. 하지만 svg는 그런 기능은 없지만 render-order속성으로 어느정도 그렇게 할 수 있다.
D3js는 svg를 손쉽게 그리는 추상계층을 제공한다.
svg를 지원하는 기능만으로 충분하지만 canvas를 사용해야 할 때도 있다, 주로 대용량의 데이터를 그릴때 캔버스가 성능이 뛰어나면 이미지로 저장가능하다.
디자인 요소가 아닌, 실용적인 표현으로 svg에 접근할때는 기본 기하학 도형에 대한 이하개 중요하다.
svg에서 도형이 크기와 스트로크를 포함한 도형의 크기는 별개이다.
도형의 경계를 중심으로 안밖으로 동일한 두께로 태두리가 그려진다.
Path의 d 속성으로 라인을 그리고 Z의 존재 여부에 따라 닫힌 path 여부가 결정된다.
보통 path를 직접 그리는 일은 없고 보통 일러스터나 D3를 이용해 그린다.
Svg는 css를 이용해 스타일링 할 수 있다.
D3js는 메서드체이닝을 할수 있다.
Data 바인딩 append 메서드 사용법
- 데이터의 종류에는 표데이터, 내포된데이터, 네트워크데이터, 지리데이터, 원시데이터, 객체데이터가 있다
- 표데이터는
tsvdsvcsv와 같은 메서드 제공 - 내포된 데이터는 객체가 다른 객체에 자식으로 중첩되는 데이터
- 네트워크 데이터는 객체와 객체간의 연결로 표현됨
- 지리데이터는 데이터를 점이나 도형으로 표현
GeoJson,topoJson이 표준 - 원시데이터는 그림 텍스트의 데이터
- 객체데이터는 스칼라값이나,
json, 자바스크립트 객체
- Json 포맷은
D3.json메서드로 처리함
transition 메서드는 변환에 애니메이션을 주고. Delay메서드는 애니메이션 시간을 지정한다.
duration 은 애니메이션 시간이고 delay 애니메이션이 처리되기 전에 지연타임을 결정한다.
2. 정보 시각화 데이터 흐름
csv 메서드나 json xml 메서드 같은 특정한 포멧을 위한 메서드로 데이터를 로딩한다.
로드 메서드의 두번째 인자는 hof 함수이며 인자가 하나일때는 데이터 객체를 나타내며, 인자가 2개일때 첫번째 인자는 에러 객체다.
csv 메서드나 json 메서드의 결과 데이터는 객체의 형태로 반환된다.
이런 로드 메서드는 비동기로 실행되므로 유의해야 한다.
D3js는 데이터 변환 메서드로 scale과 같은 메서드를 제공한다.
var newValue = D3.scale.linear().domain([500000, 13000000]).range([0, 500]);
newValue(1000000) 와 같이 사용하면 도메인에 맞는 범위의 range값이 반환된다.
range 에 blue red 와 같은 색상값을 넣으면, 그라디언트 범위에서 값을 추출할수 있다.
linear log pow ordinal 등의 메서드가 있다.
특히 quartile 메서드로는 값의 범위를 알아내는데 유용하다.
D3.nest와 같은 그룹화 메서드로 데이터의 특정 데이터를 키값을 추출할 데이터로 다시 만들수 있는 기능을 제공한다.
- min 메서드로 최소값을 구하는 예
d3.min(testArray, el => el)
- extent 메서드
extent는 최소값과 최대값을 함께 리턴하는 메서드다.
- data 메서드
data 메서드를 통해 dom과 데이터를 바인딩 할수 있고.
- enter 메서드
enter 메서드를 통해 데이터 길이에 비해 모자라는dom을 추가할 수 있다.
- exit 메서드
exit 메서드를 통해 데이터 길이에 비래 남는 dom을 제거 할 수 있다.
- insert, append 메서드
insert와 append 메서드로 선택된 dom에 요소를 추가할수 있다. 두개의 용도는 비슷 하지만 insert는 특정 위치를 지정하여 추가할수 있고
append 메서드는 맨 마지막에 붙인다.
그 밖에 ht.l attr 등이 있다.
scale 기능
데이터로부 계산되어 실제로 보여지는 그래프 픽셀의 범위는 scale 기능을 통해서 처리할 수 있다.
- 편차가 심한 데이터를 표현할 때는
다중 선형 스케일을 사용하면 좋다.- 도메인과
range값을 여러 구간에 걸쳐서 여러 값으로 설정하는 것이다.
- 도메인과
const scale = d3.scaleLinear()
.domain([0, 10, 100]) // 데이터 구간
.range([0, 200, 300]); // 출력 구간
clamp메서드를 이용하면 도메인 보다 큰 값을 표현할때 최대값이나 최서값에 제한을 두어 표현되게 할 수 있다.
데이터 바인딩
.data 바인딩은 배열의 요소가 객체라도 바인딩할수 있다. 다만 값을 표현하려면 텍스트 형태로 재가공 해야 한다.
- 아래처럼 특정 키값을 이용해 바인딩 위치를 설정할수 있고, 두번째 인자를 안주면 키값은 인덱스값이 사용된다.
const divs = d3.selectAll("div")
.data([{id:1, v:10}, {id:2, v:20}], d => d.id)
3. 데이터 주도 설계와 상호작용
on('click', callback) 와 같은 사용법으로 이벤트 바인딩이 가능하다.
transition 메서드와 delay 메서드, duration 메서드로 애니메이션 처리 가능
d3.select로 선택한 객체에 each 함수로 접근할 수 있고 콜백함수의 첫번째 인자는 바인딩 되는 데이터를 나타내고 this는 선택된 dom을 나타낸다.
.node 메서드를 실행하면 선택된 dom 요소를 리턴한다.
색상표현
d3js 의 rgb 객체는 16진수 rgb 표현을 전부 처리 가능하고, darker, brighter 와 같은 편의 메서드도 제공한다.
효과를 줄때 css를 사용해도 되지만 d3js로 효과를 편하게 주려면 인라인으로 처리하는게 좋다.
hsl 메서드도 제공하며 이건 rgb 메서드와 비슷한 역할을 한다.
interpolate와 d3.interpolateHsl 을 이용하면 d3.scale.linear()....range([yello, blue]) 가 그리는 색상 그라디언트의 우중충한 구간영역을 그라이언트 보간색상으로 대체할 수 있다.
그밖에도 help 과 lab 모델도 지원한다.
보통 d3.scale.category10 이라는 스케일 을 사용하면 자연스러운 그라디언트 생상 표현이 된다.
그 밖에도 신시아브루어에 기초하는 색상체계도 사용가능하며, 이 스케일 시스템은 지도에 사용되는 색상에 적합하다.
신시아브루어 색상체계는 colorbrewer 라는 라이브러리로 제공된다.
color Quantization = d3.scale.quantize().domain([0. max]).range(colorbrewer.Red[3]);
이미지 표현
svg에는 image 요소도 있으므로 아미지도 넣을 수 있다.
보통의 사용성으로 이미지는 텍스트와 함께 표현된다. 이미지가 텍스트를 덮으면 안되므로 append 보다는 insert메서드를 이용하여 텍스트 앞에 추가된다.
Svg객체에는 일반 DOM 객체가 제공하는 innerHTML 속성이 없음으로 주의해야 한다.
datum 메서드도 데이터바인딩 역할을 하지만 data 메서드와 틀린점은 datum은 단일 대이터 하나를 매칭시킨다.
4. 차트 컴포넌트
데이터셋마다 잘 맞는 차트는 따로 있다.
D3js는 차트를 그리기 위한 생성기, 컴포넌트, 레이아웃 기능을 제공한다.
생성기는 예를들면 차트에 path속성에 의해 그려지는 d 좌표를 손쉽게 생성해 주는 역할을 한다.
컴포넌트는 차트에 필요한 구성요소를 관리한다(예를들면 축 axis 영역을 그려주는 기능)
레이아웃은 컴포넌트들의 위치를 잡는 데이터나 정보를 관리 한다.
- axis 컴포넌트 예
taxis = d3.svg.axis().scale(yScale).orient("right")
taxis(d3.select('svg').append('g'))
tickSize로 틱의 길이, ticks로 틱의 개수를 설정가능하다.
css를 사용하면 d3로 모든 요소에 일일이 스타일을 지정하는 수고를 줄여주며 유지보수가 편해진다.
박스플롯과 같은 차트를 위해 쓰이는 사준위값은 d3의 quartile 메서드를 이용해 만들 수 있다.
ticks의 개수를 명확히 설정하더라도 d3js가 가장 보기 좋은 값으로 자동으로 만들어주기때문에 정확한개수로 안떨어질수 있다.
(ticks에 설정한 근사치로 보이게 된다)
대신 tickValues를 사용하면 뉴사용자가 원하는 틱을 정확히 설정 가능하다.
d3.svg.line().x(d=> xScale(d)).y(....) 와 같은 구현방식으로 라인 d를 그리는 함수를 만들 수 있다.
이런 패턴으로 만들어낸 라인함수는 interpolate 메서드를 지니며 라인을 그리는 방식으르 지정할수 있다.
보간법
cardinal, basis, step-before 등의 보간법 타입이 있다.
d3.svg.area 도 line 과 비슷 하지만 path에 z를 붙여 닫힌영역을 만들고 fill로 색상을 채워준다.
누적 에어리어
area의 y0접근자는 에어리어의 바닥의 경로를 결정한다.
만약 y접근자의 값에 -를 붙인 값을 y0으로 지정하면 위 아래로 대칭인 에어리어가 만들어진다.
그냥 선이 닫힌 도형을 채우고자한다면 꼭 area를 쓸 필요는 없다. path에 z로 닫아주기만 하면 된다.
하지만 누적에어리어 차트같은 걸 만드려면 area헬퍼를 써야한다.
누적 에어리어를 그리려면 이전에 그린 선의 y값을 현재 그리는 선의 y0값으로 정해야 하는데 이를 쉽게 처리하기 위한 stack함수를 d3에서 제공한다.
5. 레이아웃
레이아웃은 특정 차트를 그리기 위해 설정을 하는 기능이다.
layout.histogram
d3.layout.histogram()은 막대그래프를 d3로 쉽게 그리기 위한 설정을 만들어준다.
레이아웃은 추상화를 통해 표현할 데이터의 속성을 손쉽게 바꾸서 적용할수 있는 전략을 만들어준다.
(버전4 부터는 d3.histogram() 으로 인터페이스가 변경 됬다고 함)
(d3.layout.pie()([1,2,3]) 에서 1,2,3은 실제로 그릴 데이터셋)
파이차트
파이차트의 생성기는 d3.svg.arc()를 사용한다.
레이아웃은 결국 특정우타입의 차트를 위한 데이터를 쉽게 만들기 위한 추상화를 제공하는 것이다.
svg.arc 에 innerRadius 를 설정하면 도넛을 만들수 있다.
레이아웃의 정렬기능이 활성화되어 있으면 키가 변하면서 애니메이션이 부적절하게 일어나므로 데이터 순사를 유지하기 위해 .sort(null)로 옵션을 꺼주는게 좋다.
attrTween 으로 함수를 연결하면 애니메이션의 확대 축소를 방지하여 깔끔하게 표현가능하다.
서클팩 레이아웃
계층구조를 표햔할 땐 서클팩 레이아웃을 사용한다.
레이아웃은 생성기에 넣을 데이터를 그래프 형식에 ㅜ맞게 포매팅 하는 수고를 덜어준다.
category10 scale을 사용해도 좋지만, 데이터에 기반한 정확산 scale를 새팅하려면 liner같은 스케일을 사용하는게 좋다.
서클 팩 레이아웃의 padding 메서드로 원과 원 사이의 거리를 설정할수도 있다.
트리 레이아웃
d3.layout.tree() 트리 레이아웃 제공
실제로 선을 그릴때는 d3.svg.diagonal() 생성기를 사용한다>
트리 레이아웃은 treeChatr.links(treeChart(data)) 메서드를 제공한다.
diagonal 생성기의 projection 메서드로 수직 수평 방향을 설정할 수 있다.
projection으로 x와 y좌표를 바꾸면 수직방향으로 표현할 수 있다…
d3.behavior.zoom()을 이용하면 사용자가 줌 동작을 이용하도록 구현할 수 있다.
zoomStart, zoomed, zoom이벤트를 등록할수 있으며 비용이 많이드는 작업은 start와 end에만 넣는것이 좋다.
d3.svg.dianoal.radial()를 사용하면 방사형으로 그릴 수 있다
방사형으로 그릴땐 회전시키며 그리므로, 차트의.크기를 줄이고 transform으로 노드 위치를 조정한다.
스택레이아웃
누적 에어리어를 쉽게 그릴 수 있는 레이아웃도 제공한다 스택레이아웃 이다.
스택레이아웃은 offset메서드를 제공하여 영역의 상대 위치를 결정할 수 있다.
offser.('silhouette') 과 같이 사용하여 수평으루기준으로 누적영역을 그린다.
oreder(inside-out) 은 영역을 그리는 순서를 위 아래로 펼쳐 그리도록 해준다.
스택레이아웃은 꼭 에어리어 누적을 그리는곳에만 쓰이는 것이 아니라, 막대그래프도 누적으로 쉽게 그릴 수 있다.
생키다이어그램
생키다이어그램은 범주의 흐름을 시각적으로 나타내게 도와준다.
생키다이어그램은 노드와 엣지 두가지 부류의 객체로 표현된다.
엣지는 링크 연결을 뜻한다.
생키레이아웃은 d3기본 레이아웃이 아닌 사용자가 만든 플러그인 형태로 제공된다.
플러그인 형태는 문서는 빈약하지만, 생태계가 풍부하고 유용하다.
d3.sankey()로 레이아웃 생성
생키레이아웃에서 layout메서드는 링크들의 연결 위치를 최적화해주며. 데이터가 복잡할수록 여러번 호출해줘야 링크흐름이 알아보기쉽게 정돈된다.
(0.12 버전 이후에는 한번만 실행해도 되도록 개선됨)
워드 클라우드 레이아웃
워드 클라우드 .레이아웃은 플러그인 형태로 제공된다.
D3.layout.cloud() 는 깃헙에서 다운로드 가능하다.
6. 네트워크 시각화
네트워크데이터는 엣지목록이라고 알려진 데이터 포멧이 가장 간단하다.
소스, 타겟, 가중치의 정보를 가진 네트워크데이터는 단방향으로만 연결된다.
인접행렬은 엣지를 선 없이도 표햔할수 있다.
X축과 Y축에 각각 노드를 놓고, 두 노드가 연결되어 있으면 격자에 색으루 채운다. 강하게 연결될수록 진하게 채운다.
인접행령 차트는 레이아웃이 없으므로 직접 기본제공되는 생성기만으로 그려야 한다.
D3.scale.ordinal()은 교유한 아이디의 배열을 사용하고 .rangePoint() 메서드는 각각에 고유한 아이디를 스케일에 수치레이블을 연결하여 보여준다.
원도 다이어그램
네트워크는 원호 다이어그램으로도 나타낼수 있다. 원호 다이어그램은 레이아웃을 제공하지 않고 예제도 적지만, 원리는 간단하다. 원호차트는 노드간에 거리가 멀수록 더 높은 원호를 그린다.
classed 메서드로 특정 클래스명 on off 가능.
힘방향레이아웃
svg:defs에 마커를 정의하고, 필요할때마다 원하는 위치에 연결할 수 있다.
d3.selectAll("line").attr("marker-end", "url(#Triangle)"); 와 같은 코드로 defs로 정의한 마커를 사용 가능하다.
너무 복잡한 시각화 네트워크는 머리카락이 언킨듯 복잡해 보여서 비판받기도 하는데 이런 현상을 헤어볼이라고 부른다. 머리카락이 엉킹것 같은 모양을 표현한 용어다.
-
엣지가중치
- 연결간에 강도를 나타낸다.
-
중심성
- 노드들중 중요한 노드들은 중심성이 높다. 중심성을 측정하는 방법은. 다양하며 네트워크 유형에 따라 달라진다.
-
연결정도
- 연결정도 중심성 이라고 하며 노드에 연결된 엣지의 개수로 결정한다. 가중치 연결정도란 노드에 연결된 가중치의 합을 나타낸다. 연결되는 방향과 관련하여 노드로 들어가는 연결을 내향연결정도, 반대로 나가는 연결을 외향연결정도라고 불른다.
-
척력
- 힘 방향 레이아웃은 노드간에 척력을 설정할수 있는데, 음수로 줄수록 척력이 강해진다. 척력을 설정하는 이유는 노드간에 보여지는 거리를 조절하여 가독성이 더 좋게 만들 수 있기 때문이다.
-
중력
- 노드가 서로 밀어내더라도 차트 밖으로 넘쳐 보이지 않게 하려면 중력을 설정해야 한다.(설정하지 않으면 기본값은 1이다)
-
엣지거리
- 엣지거리는 노드간에 연결이 너무 멀거나 가까워지지 않게 유지하려는 값을 설정한다.
-
엣지강도
엣지 강도는 그 거리로 얼마나 강하게 끌어당길 것인가에 대한 힘의 세기를 말한다.
힘-방향 레이아웃은 처음에 빠르게 움직이다가 점점 느려지면서 노드의 위치가 최적이될때 멈춘다.
이런 애니메이션을 .start, .end, .resume 과 같은 메서드로 컨트롤 할수 있다.
.tick 메서드를 이용하여 단계별로 하나씩 진행시킬 수도 있다.
.drag 메서드는 사용자가 노드를 잡고 움직일수 있게 해준다.
fixed 속성을 사용하면 애니메이션 되는 동안 노드의 위치가 변하지 않도록 특정 노드를 고정시킬수 있다.
아래 코드와 같이 exit된 엘리먼트들에 스타일을 준후 애니메이션이 완료되면 지우는 방식으로 작업할수 있다.
.exit().transition().duration(3000).style('opacity', 0).remove()
데이터에 키값을 바인딩 해놨으므로 기존 노드들의 형태를 유지하면서 애니메이션 되게 된다.
- 위치 애니메이션
힘 방향 레이아웃에서는 노드와 좌표를 x, y는 물론 px, py 도 세팅해줘야 하는데 px, py 는 애니메이션으로 이동하기 전에 좌표를 말한다.
힘 방향 레이아웃은 컴퓨터 리소스를 많이 사용하므로 노드의 개수가 너무 많지 않도록 해야 한다. (IE기준 노드 100개 이하) 거리를 제한하면 레이아웃 구조가 더 안예쁘게 흐트러져 나오지만 더 빨리 실행된다. chargeDistance() 로 설정해보며 최적의 값을 찾아보는게 좋다.
7. 지리 공간 정보 시각화
지도 데이터의 표준은 GeoJSON 이다.
GIS 관련 프로그램들은 보통 GeoJSON 데이터를 내보낼수 있는 기능이 있다.
지도를 그리는 여러 기법들이 있는데 그 방법을 도법이라고 하며 만드려는 목적에 따라 적절한 도법을 골라야한다.
메르카도르 투영법
지도를 평면에 그리는 걸 투영법이라고 하는데, 메르카도르 투영법이 사실상 표준이다.
d3에서 메르카도르 투영법을 사용하기 위해서는. 플로그인 d3.geo.projection.js을 추가하여 사용해야 한다.
const projection = d3.geo.mercator(); // 메르카도르 투영법 생성
var geoPath = d3.geo.path.projection(projection); //으로 지도 path를 그리는 함수 생성
메르카도르 투영법은 기본값으로 사용시, 일부 세계만 svg에 그려준다.
메르카도르의 경우 공간의 너비를 2로 나눈 값에 몫을 pi 로 나누면 세계 전체를 보여주는 축적 비율을 얻을수 있다.
// 세계지도 표시 예
ator().scale(80).translate([width / 2, height / 2])
몰바이데도법
몰바이데도법은 남극의 크기면적을 유지하지만 모양과 각도를 외곡시킨다
datum은 하나의 데이터점을 배열에 넣을 필요없이 바인딩하는 메서드이다.
지도에 경위선망 그리기
d3.geo.gracitule()로 경위선망을 만들고 기존에 데이터 세팅되어 출력한 지도 위에 datum을 이용해 변경 데이터만 새롭게 데이터바인딩 가능하다.
D3에서 제공하는 다중선 스트링은 여러개의 선을 하나의 path로 그릴 수 있으므로 경위선망을 그리기에 적합하다.
정사도법(지구본)
정사도법을 이용하면 Webgl 없이도 지구본을 만들 수 있다.
// 정사도법 예
projection = d3.geo.orthographic();
d3.mouse는 svg 에 있는 마우스커서의 위치를 반환한다
이 투영법은 구면의 뒷면을 기본으로 감추지 않는다. 구면 뒷부분을 지우려면 clipAngle 속성을 사용하여 해결할 수 있다.
selectorAll().data() 를 사용하면 기존 바인딩된 데이터를 다시 가져와서 확인할 수 있다.
de.geo.area() 로 지역의 대략적인 면적을 구할수 있다.
위성도법
위성도법을 사용하면 위성에서 본듯한 뷰를 그릴수있다.
D3.geo.satellite()
다른 도법과 비슷하지만 tilt, distance와 같은 특수한 속성을 갖는다. tilt로 내려다보는 각도와 distance로 바라보는 거리를 세팅 가능하다.
TopoJson
TopoJson은 지리데이터의 표준이다.
TopoJson은 지형의 이웃하는 국경선을 기준으로 데이터를 저장하며, geoJson보다 용량면에서 효율적이다.
TopoJson을 d3에서 쓰려면 geojson으로 변환해야 한다.
topojson.js를 추가하고 feature메서드로 변환할수 있다.
Topojson.merge기능을 통하여 지도끼리 서로 통합하는 기능도 제공한다. 특정조건에 맞는 지형을 필터하여 지도에 보여주거나 할 수 있다.
이 데이터 형식의 장점은, 지형이 국경선 정보 즉 원호를 공유하는 방식이므로 인접하는 이웃 지형들을 쉽게 알 수 있다.
TopoJson.neighbors()
D3.geo.tile과 Mapbox 같은 기업에서 제공하는 데이터를 이용하면 지도에 이미지를 손쉽게 입힐수 있다.
8. D3를 이용한 DOM 조작
const i = d3.interpolateNumber(10, 20);
console.log(i(0)); // 10 (시작값)
console.log(i(0.5)); // 15 (중간값)
console.log(i(1)); // 20 (끝값)
9. 생략
10. 레이아웃과 컴포넌트 만들기
레이아웃은 화면에 출력하려는 데이터셋을 조작하려는 함수이자 객체다.
데이터를 처리하는 함수를 만드는 객체를 만들어야 한다.
D3.layout.grid = () => {
...
}
10.2 컴포넌트 만들기
D3.svg.legend = () => {
...
}
11. 대형 데이터 시각화
D3.RANGE()로 임의에 개수의 배열 생성이 가능하다
Svg대신 canvas 그리면 속도가 빠르다.
- 아래 예제처럼 하는 방식으로 컨텍스틑 캔버스로 바끌수 있다
geopath = d3.geo.path().projectioin(projection);
geopath.context()
캔버스를 사용하면 성능이 향상되지만 지도르르확대하면 svg만큼 선명하게 보이지는 않는다.
캔버스를 사용하면 상호작용을 자유롭게 제공하지 못하는 단점이 있다.
상호작용이 필요한 그림은 svg로 상호작용이 없는 것은 캔버스로 그리면 성능과 효용을 둘 다 잡을 수 있다.
확대나 축소같은 작업을 할때는 성능에 유리한 캔버스로 그리고. 각각의 객체에 마우스 오버 같는 효과를 줘야할땐 svg로 그리면 효율적이다.
특히 d3.geo.path는 캔버스로 그리는 기능까지 갖추고 있어서 편리하다.
하지만 모든 형식이 캔버스를 지원하지는 않는다.
대형 네크워크 차트를 다루려면 캔버스로 그리는 함수를 직접 작성해야한다.
forcetick마다 그려지는 엣지를 캔버스로 직접 그리면 된다.
D3.geom.quadtree()를 사용하면 공간탐색의 성능을 향상시킬 수 있다.
화면을 사분면으로 나워서 탐색하므로 모든 공간을 다 탐색하지 않고도 탐색할수 있다.