D3.js 데이터 바인딩을 해보자

sun202x·2022년 10월 28일
0

D3.js

목록 보기
3/4
post-thumbnail

지난 글에 이어서 D3.js를 사용하여 데이터 시각화를 하기위한 두 번째 단계로 데이터 바인딩을 알아보자.
지난 예제를 보면서 조금 이해가 가지 않았던 부분들이 데이터 바인딩 파트에서 다소 해소되는 것을 느낄 수 있으리라고 생각한다.

데이터 시각화

데이터 시각화를 말하기 이전 데이터와 정보의 차이를 먼저 짚어 보자.

📝 데이터는 가공되지 않은 진실을 뜻한다. 가공되지 않았다는 것은 그 의미를 알아내는 과정을 거치지 않았음을 말해준다. 정보는 가공되지 않은 진실에서 어떤 의미를 밝힌 후의 결과를 의미한다.

Rob P., S. Morris, and Coronel C. 2009

데이터 시각화 분야에서 정보는 더 이상 단순히 가공된 사실의 결과가 아니라 그 사실에 대한 시각화 메타포(metaphore) 이기 때문에 더욱 풍부한 해석을 제공해 준다. 그렇기 때문에 데이터에 대한 제작자의 의도를 전달하는 것이 다른 무엇보다 중요하다.

입력-업데이트-종료 패턴

편의상 앞으로 설명하기 위한 데이터 집합을 D라고 하고 시각화 집합을 V라고 하겠다.

D3에서는 DV의 관계를 정의하는 방법으로 입력-업데이트-종료(enter-update-end) 패턴을 사용한다. 이 패턴을 이해해야지만 D3의 데이터와 시각화 요소 바인딩 방식을 알 수 있다.

업데이트

먼저 해당 데이터 요소를 나타내는 모든 시각화 요소를 아래와 같이 나타낼 수 있다.

D ∩ V

데이터와 시각화 도메인 양쪽 모두에 나타나는 요소들을 뜻한다. D3에서는 selection.data(data) 함수가 이런 교집합 선택을 위해 사용할 수 있다. 이제 이런 선택을 가지고 여러가지 수정자 함수를 통해 모든 요소들의 업데이트를 할 수 있게 된다. 이 선택 모드를 업데이트 모드 라고 한다.

입력

다음으로 아직 시각화가 되지 않은 데이터는 아래와 같이 나타낼 수있다.

D / V

D와 V의 차집합은 아직 시각화 되지 않은 데이터를 뜻하며, 이러한 부분집합에 접근하려면 enter()를 통해 접근할 수 있다. enter() 함수는 이러한 부분집합에 대한 새로운 선택자를 반환하고 정규 수정자 함수는 주어진 데이터 요소를 표현하는 새로운 시각화 요소들을 만들기 위해 연결된다. 이러한 선택 모드를 입력 모드 라고 한다.

종료

마지막으로 더이상 시각화에 대응하는 데이터가 없는 시각화 요소는 아래와 같이 나타낼 수 있다.

V / D

이러한 시각화 요소들은 데이터 집합에서 요소들을 제거할 경우 생겨난다. 해당 부분 집합을 선택하기 위해서는 exit()함수를 통해 접근할 수 있다. exit() 함수가 호출되면 유효한 데이터와 연결되지 않은 모든 시각화 요소를 포함하는 선택자를 반환하게 된다. 수정자 함수는 더이상 시각화 할 필요가 없는 요소들을 제거하기 위해 연결된다. 이 선택모드를 종료 모드라고 한다.

배열 데이터 바인딩

D3 시각화에서 데이터는 배열로 정의되는 것이 일반적이다. 아래 코드에서 배열 데이터가 시각화 요소로 바인딩되는 것을 확인할 수 있다.

// 시각화할 데이터
var data = [10, 15, 30, 50, 80, 65, 55, 30, 20, 10, 8];

// render 함수를 통해 DOM을 생성하고 화면에 시각화 요소들을 그리게 된다.
function render(data) {
  // Enter
  d3.select("body").selectAll("div.h-bar")
    .data(data)
  	// 아직 시각화 되지 않은 데이터 요소들을 포함하는 선택자를 반환한다.
    .enter()
    .append("div")
    .attr("class", "h-bar")
    .append("span");

  // Update
  d3.select("body").selectAll("div.h-bar")
  	// 현재 데이터가 존재하고 시각화된 요소들을 포함하는 선택자를 반환한다.
    .data(data) 
    .style("width", function (d) {
      return (d * 3) + "px";
    })
    .select("span")
    .text(function (d) {
      return d;
    });

  // Exit
  d3.select("body").selectAll("div.h-bar")
    .data(data)
  	// 데이터가 존재하지 않는 모든 시각화 요소들을 포함한 선택자를 반환한다.
    .exit()
  	// 제거한다.
    .remove();        
}

// 1.5초 마다 랜덤수를 생성하여 기존 첫 요소를 제거하고 추가한다.
// 유동적으로 그래프가 변경되게 된다.
setInterval(function () {
  data.shift();
  data.push(Math.round(Math.random() * 100));
  render(data);
}, 1500);

render(data);

위 코드에서 입력 모드일 때 아직 생성되지 않은 div.h-bar를 선택하는 로직을 확인할 수있다.
일반적이라면 이미 생성되지 않은 요소를 선택하기 때문에 문제가 생길 것 같지만, D3에서는 시각화 집합을 만들기 위해 div.h-bar가 반드시 있어야 한다는 것을 본질적으로 선언하는 것을 의미한다.

함수 바인딩

javascript의 함수는 객체이므로 D3에서는 이러한 점을 잘 이용하여 함수를 데이터로 전달할 수 있다.

var data = [];

var next = function (x) {
  return 15 + x * x;
};

var newData = function () {       
  data.push(next);
  return data;
};

function render(){
  var selection = d3.select("#container")
    .selectAll("div")
  	// 각 요소가 함수인 배열을 데이터로 전달한다.
    .data(newData);

  // 입력 모드 처리
  selection.enter().append("div").append("span");

  // 종료 모드 처리
  selection.exit().remove();

  selection.attr("class", "v-bar")
    .style("height", function (d, i) {
      // 전달받은 함수 요소를 호출하여 값을 생성한다.
      return d(i) + "px";
    })
    .select("span")
      .text(function(d, i){ 
        return d(i);
      }); 
}

setInterval(function () {
  render();
}, 1500);

render();

배열 다루기

D3에서는 배열을 다루기 위한 몇가지 유틸 함수들이 제공된다.

  • d3.min 배열에서 가장 작은 요소를 찾아 반환한다.
  • d3.max 배열에서 가장 큰 요소를 찾아 반환한다.
  • d3.extend 배열에서 가장 큰 요소와 작은 요소를 동시에 찾아 반환한다.
  • d3.sum 배열의 모든 요소의 합을 반환한다.
  • d3.medium 배열의 중간 값을 찾아 반환한다.
  • d3.mean 배열의 평균을 계산하여 반환한다.

위 유틸 함수들 말고도 유용한 여러 유틸 함수들이 존재하며 다른 유틸 함수들의 정보는 여기서 확인할 수 있다.

정리

D3에서 데이터 시각화를 위한 데이터 바인딩을 알아보았다. 몇가지 유틸 기능(필터링, 정렬)같은 것들도 더 존재하니 궁금하다면 공식 사이트에서 문서를 확인해보시면 좋을 것 같다.

Reference

다양한 레시피로 보는 D3.js 쿡북

profile
긍정적으로 살고 싶은 개발자

0개의 댓글