D3의 Tutorial 중 가장 기본적인 BarChart 그리기를 정리한 것.

Tutorials

1. Bar차트 그리기

1. 요소 선택하기

  1. selector를 쿼리하여 element를 선택할 수 있음.(ex. d3.select('div') or d3.selectAll("section"))
  2. .append(), html()등의 메소드를 이용하여 간단하게 element 편집 가능.

2. 메소드 체이닝

  1. select()를 통해 가져온 element를 method chaining을 이용하여 보다 편하게 여러 메소드를 걸 수 있음.
    d3.select("body")
     .style("color", "black")
     .style("background-color", "white");
    
  2. 체이닝은 document 계층에서 자식에게만 적용됨. 즉, 다른 자식을 생성했다면, 더 이상 해당 element에 체이닝 불가. -> 변수를 이용하여 원하는 reference를 관리.

3. 차트 그리기

class가 chart인 div태그가 있다고 가정하자. 해당 요소 안에 d3를 이용하여 차트를 그리는 방법은 다음과 같다.

d3.select(".chart")
  .selectAll("div")
    .data(data)
  .enter().append("div")
    .style("width", function(d) { return d * 10 + "px"; })
    .text(function(d) { return d; });

위의 코드를 순서대로 한 줄씩 풀어보면..

  1. selector를 이용하여 차트를 그릴 영역을 선택
var chart = d3.select(".chart");
  1. data join을 위한 selection을 정의
    1. div.chart 안에는 data가 담긴 div가 있을수도 없을수도 있음.
    2. d3에서 정의된 selection 객체를 반환하는데, 이 객체를 통해 데이터를 바인드하고, 데이터에 대응하는 객체를 다룰 수 있는 기능을 제공함.
      var bar = chart.selectAll("div");
      
  2. Data join을 위해 정의한 영역에 data를 bind
    1. Data Join은 데이터의 변경에 따라 element를 만들고, 갱신하고, 삭제하는데에 있어서 많이 사용되는 패턴이다.
    2. 이러한 패턴을 따라 개발함으로써, 거의 동일한 코드를 가지고 각기 다른 데이터를 시각화할 수 있기 한다.
      var barUpdate = bar.data(data);
      
  3. (현재) selection이 비어있기 때문에 updateexit 메소드의 리턴(selection)도 비어있다. 그러므로 현재 비어있는 데이터를 다루는 enter 메소드의 리턴인 selection들에 새로운 데이터를 넣기만 하면 된다.
    var barEnter = barUpdate.enter().append('div');
    
  4. 새로 생긴 div들의 selection인 barEnter에 너비를 준다.
    barEnter.style("width", function(d){ return d*10 + "px"; });
    
  5. 위 과정을 통해 생성된 element들은(div) Data Join 을 통해 생성되었기 때문에 각각의 div들은 모두 data가 묶여있음.
  6. 이후에 각 div에 data 수치를 text로 넣어준다.
    barEnter.text(function(d){ return d; });
    

4. 규모에 맞게 확장하기

위 코드의 한 가지 약점은 코드에 직접 들어간 숫자인 10이다.(4번의 return d*10 부분) 이렇게 되면, 10이라는 숫자에 의존적인 차트가 나오게 됨.

이것을 linear scale을 이용하여 의존성을 분리시킬 수 있음. D3의 스케일은 범위를 보여주기 위해 data space(domain)으로부터 정해진다.

var x = d3.scale.linear()
        .domain([0, d3.max(data)])
        .range([0,420]);

x를 분리하여 차트를 생성하는 그래프와, 스케일을 지정하는 코드를 분리하였다. 위 코드를 기존 코드에 적용시킨다면

d3.select(".chart")
    .selectAll("div")
    .data(data)
    .enter().append("div")
    .style("width", function(d) { return x(d) + "px"; })
    .text(function(d) { return d; });

2. Bar Chart 그리기 II

1. SVG란?

Scalable Vector Graphics의 약자로 곡선이나 기울기, 꺾인선, 면 등을 표현할 수 있게한다.

2. 데이터 불러오기

tsv파일을 통해 데이터를 불러오려고 한다 가정해보자. 이 과정을 위해서는 파일을 웹 서버에서 다운받고, 파싱하여 JS의 object 형태로 바꾸는 과정이 필요하다.

d3.tsv메소드를 이용하면 이러한 과정을 한 번에 수행 가능하다.

Data를 불러오는 과정은 다운로드의 비동기적 특성때문에 복잡해질 수 있다. d3.tsv를 이용한다면, 백그라운드에서 파일을 즉시 다운로드하여 다운로드가 끝난 후 callback이 동작하는 형태로 작동된다.

// 1. 다운로드 전에 동작하는 코드
d3.tsv("data.tsv", function(error, data){
    // 3. 다운로드가 된 후 동작할 코드
});
// 2. 다운로드 중에 동작할 코드

차트를 개발하는데에 있어서 두 단계로 나누어 개발하는 것이 좋다. 첫 번째 단계는, page가 로드되면서 데이터가 준비되기 전에 할 수 있는만큼 차트를 그릴 준비를 해야한다. 차트의 사이즈를 정한다거나, 변수를 초기화하는 작업 등을 미리 하여 차트를 그리기 전에 차트에 필요한 준비를 끝내는 것이다. 두 번째 단계는 데이터가 로드된 이후 callback 함수 안에 차트를 그리는 코드를 작성한다.

var width = 420,
    barHeight = 20;

var x = d3.scale.linear()
    .range([0, width]);

var chart = d3.select(".chart")
    .attr("width", width);

d3.tsv("data.tsv", type, function(error, data) {
  x.domain([0, d3.max(data, function(d) { return d.value; })]);

  chart.attr("height", barHeight * data.length);

  var bar = chart.selectAll("g")
      .data(data)
    .enter().append("g")
      .attr("transform", function(d, i) { return "translate(0," + i * barHeight + ")"; });

  bar.append("rect")
      .attr("width", function(d) { return x(d.value); })
      .attr("height", barHeight - 1);

  bar.append("text")
      .attr("x", function(d) { return x(d.value) - 3; })
      .attr("y", barHeight / 2)
      .attr("dy", ".35em")
      .text(function(d) { return d.value; });
});

function type(d) {
  d.value = +d.value; // coerce to number
  return d;
}