D3.js의 스케일을 사용해보자

sun202x·2022년 11월 18일
0

D3.js

목록 보기
4/4
post-thumbnail

책에서 예제로 쓰고 있는 D3.js의 버전은 3.2.8이며 게시글에 작성된 예제들이 최신 버전의 API와 차이가 있을 수 있으니 참고 바랍니다.

데이터 시각화에서 반복적으로 수행하게 될 핵심 작업은 데이터 도메인에서 시각화 도메인으로 값을 매핑하는 작업이다. 따라서 효과적이고 정확하게 데이터 요소를 시각화 메타포(metaphore)로 매핑 하는 것이 데이터 시각화에서 가장 중요한 일이라고 할 수 있다.

스케일(scale)이란?

짧게 말해서 스케일(scale)은 수학 함수로 생각할 수 있다. 이는 자바스크립트 함수처럼 명령형 프로그래밍 언어에서 정의된 함수와는 개념이 다르다. 수학에서 함수는 두 집합 사이의 매핑으로 정의된다.

위 정의로 미루어 보아 수학적 개념의 함수는 우리가 해야할 일(시각화 도메인으로의 매핑)에 적합하다는 것을 알 수 있다. D3.js에서는 이러한 스케일을 다양한 구조로 제공 하는데, 값의 매핑 뿐만 아니라 전환이나 축(axis)과 같은 다른 구성들로도 사용될 수 있다.

스케일을 사용함에 있어서 중요한 개념이 있는데, 바로 도메인(domain, 정의역)범위(range, 치역)이다. 우리는 D3.js의 스케일을 통해 데이터 도메인 집합(domain)에서 시각화 도메인 집합(range)로 매핑할 수 있게 된다.

📝 아무래도 수학적인 개념이 들어간 내용이다 보니 글만 봐서는 이해가 부족할 수 있다. 좀 더 수학적인 개념의 접근을 보고 싶다면 책을 참고하길 바란다.

📝 책에서는 두 집합 사이의 관계에 대해서 설명하며 스케일(함수)은 두 집합 간의 한 요소에서 한 요소로의 매핑이라고 설명하고 있다.

양적 스케일

D3.js에서 가장 많이 사용하는 선형, 거듭제곱, 로그 스케일을 포함하는 양적 스케일에 대해 살펴보자.

render 함수

우선 지난 포스트에서 다뤘던 입력-업데이트-종료 패턴으로 작성된 render 함수를 살펴보자.

// 1~10 까지의 요소를 포함하는 data 변수를 생성한다.
var max = 11, data = [];
for (var i = 1; i < max; ++i) data.push(i);

// 입력 인자로 데이터, 스케일 함수, DOM 셀렉터가 전달된다.
function render(data, scale, selector) {
  // 입력
  d3.select(selector).selectAll("div.cell")
    .data(data)
    .enter().append("div").classed("cell", true);

  // 종료
  d3.select(selector).selectAll("div.cell")
    .data(data)
    .exit().remove();

  // 업데이트
  d3.select(selector).selectAll("div.cell")
    .data(data)
    .style("display", "inline-block")
    .text(function (d) {
      // text 반환시 scale 함수가 적용된 것을 확인할 수 있다.
      return d3.round(scale(d), 2);
    });
}

위 로직에서 업데이트 패턴으로 작성된 chaining functiontext 함수 내부에서 d3.round 함수와 함께 scale 함수가 사용된 것을 확인할 수 있다. d3.round 함수는 scale 함수의 결과를 반올림 해주는 함수이다.

위와 같은 형식으로 domainrange로 변환하여 시각화 메타포로 매핑하는 것을 확인할 수 있다. render 함수를 먼저 확인했으니, 이제 scale 함수를 살펴보자.

선형 스케일

d3.scale.linear 함수를 통해 기본 domain 집합 [0, 1]과 기본 range 집합 [0, 1]을 갖는 선형 양적 스케일을 생성할 수 있다. 기본 스케일은 본질적으로 숫자에 대한 항등 함수(identity function) 임을 보여준다.

📝 domain의 요소 값과 매핑된 range의 요소 값이 동일하기 때문에 기본 스케일은 항등 함수라고 한다.

기본 스케일로는 기대하는 결과를 만들어내지 못하므로 domain 함수와 range 함수로 추가적인 사용자 정의를 할 수 있다.

// 항등 스케일
var linear = d3.scale.linear()
  .domain([1, 10])
  .range([1, 10]);

domain 집합의 범위와 range 집합의 범위를 다르게 하여 스케일을 설정할 수도 있다.

// 선형 스케일
var linearCapped = d3.scale.linear()
  .domain([1, 10])
  .range([1, 20]);

거듭제곱 스케일

d3.scale.pow 함수를 통해 지수가 1인 거듭제곱 스케일을 생성할 수 있다. exponent 함수를 통해 지수를 설정할 수 있다.

// 간단한 거듭제곱 스케일
var pow = d3.scale.pow().exponent(2);

다음 거듭제곱 스케일 함수는 roundRange함수와 같이 작성되었다. roundRange 함수는 기본적으로 range 함수와 동일하지만 결과 값을 반올림 한다는 점이 다르다.
이는 데이터 시각화 요소로 매핑하는 작업을 할 때 px 단위로 변환 함에 있어서 유리하다. px 계산시 소수점 이하의 값을 피하는게 렌더링 과정에서의 anti-alias를 방지하는데 좋기 때문이다.

// 거듭제곱 스케일
var powCapped = d3.scale.pow()
  .exponent(2)
  .domain([1, 10])
  .rangeRound([1, 10]);

로그 스케일

d3.scale.log함수를 통해 로그 스케일을 생성할 수 있다. 기본 로그 스케일은 밑을 10으로 가진다.

var log = d3.scale.log();

로그 스케일에서도 마찬가지로 domainrange를 설정할 수 있다.

var logCapped = d3.scale.log()
  .domain([1, 10])
  .rangeRound([1, 10]);

D3.js에서는 더 다양한 양적 스케일을 제공한다. 더 살펴 보고 싶다면 해당 링크를 참조 바란다.

시간 스케일

가끔 시간과 날짜에 민감한 데이터 집합을 분석할 때가 있는데, D3.js에서는 이런 유형의 매핑을 돕기 위해 내부적으로 시간 스케일을 제공한다.

var start = new Date(2013, 0, 1),
    end = new Date(2013, 11, 31),
    range = [0, 1200],
    time = d3.time.scale()
		.domain([start, end])
		.rangeRound(range),

위 로직을 보면 d3.time.scale 함수를 통해 시간 스케일 함수를 생성하는 것을 확인 할 수 있다. 양적 스케일과 동일하게 시간 스케일도 마찬가지로 domain, range 함수를 통해 설정할 수 있으며, 이 때 domain 집합의 범위는 특정 구간의 일자가 되는 것을 확인할 수 있다.

📝 시간과 관련된 데이터를 시각화 할 때, D3.js에서 제공해주는 시간 포매터(time formatter)를 사용할 수 있다. 특히 Date 객체를 사용할 때 굉장히 유용하다. 자세한 내용은 여기서 확인할 수 있다.

순서 스케일

때때로 ["a", "b", "c"]["#1f77b4", "#ff7f0e", "#2ca02c"]와 같이 데이터의 순서에 따른 매핑이 필요할 때가 있다. D3.js에서는 스케일을 사용해 이런 종류의 매핑을 할 수 있다.

var max = 10, data = [];
for (var i = 0; i < max; ++i) data.push(i);
    
var alphabet = d3.scale.ordinal()
  .domain(data)
  .range(["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]);

d3.scale.ordinal 함수를 통해 순서 스케일이 생성됐다. 이 스케일의 domain 함수는 정수 배열을, range 함수는 a~j 까지의 문자열 배열을 전달받는다.

이런 식으로 손쉽게 스케일을 통해 매핑을 수행할 수 있다. 예를 들어 alphabet(0)a를 뜻하고 alphabet(4)e를 반환한다.

순서 스케일을 사용하면 파이 차트나 버블 차트에 각각의 다른 색상을 입히는 것들을 할 수 있다. 시각화에서는 다양한 요소에 다양한 색상을 설정하는 것이 매우 일반적인 작업이라 유용하게 사용할 수 있다.

📝 D3.js는 다양한 내장 순서 색상 스케일을 제공한다.

Reference

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

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

0개의 댓글