D3.js Scale

D3.js Scale

d3.js 의 scale은 어떤 범위를 숫자를 다른 범위로 숫자로 변경해서 그릴려고 하는 영역 공간에 그 크기를 자동으로 조절하여 시각화 하는데 사용하는 함수가 바로 scale 메소드 이다.

scale API

  • d3.scaleTime()
  • d3.scaleLinear()
  • d3.scalePow()
  • d3.scaleLog()
  • d3.scaleIdentity()

예를 들어 가장 흔하게 사용하는 변경은 백분률이다. 0에서 4955의 범위가 있을 때 2345가 어디쯤인지 감을 잡기 위해 다음 같은 방식으로 백분률을 고친다.

2345 / 4955 * 100 = 47.32

이를 통해 전체를 100으로 본다면 47정도의 위치에 있는 숫자인지 감을 잡을 수 있다. 이를 구현한게 d3.js에서 scale 메소드 이다.

1
2
var scale = d3.scaleLinear().domain([0, 4955]).range([0, 100]);
console.log(scale(2345)); //47.32

scaleTime과 scaleLinear를 다르다. 일단 위의 함수로 생성된 scale함수는 추가적인 속성을 설정할 수 있는데 그 중 가장 중요한게 domain과 range 이다.
둘 다 배열 1개를 인자로 받고 배열 안에 2개의 원소로 시작과 끝의 범위를 기술한다. domain이 실제 값의 범위라면 range가 백분률처럼 변환하고 싶은 값의 범위이다.

range에서 시작과 끝을 반대로 기술하여 역으로 값이 나오게할 수도 있다는 점이다. 이 방법은 실제로 많이 사용되는데 그래프가 아래서 위로 솓아오르는게 자연스러운 반면 svg의 좌표계는 젤 위가 0이고 아래로 갈수록 증가하는 형태라 값을 거꾸로 기술하는 편이 더 시각적으로 좋기 때문이다.

예제

1
2
3
4
5
6
7
-data.cvs
x,y,r
50,50,1
100,150,3
150,50,5
200,150,7
250,50,9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function render(data) {
var circle = svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', function(d) {
return rScale(d.r);
})
.attr('fill', function(d) {
return colorScale(d.r);
});
}

function type(d) {
d.x = +d.x; // parseFloat(d.x)
d.y = +d.y; // parseFloat(d.y)
d.r = +d.r; // parseFloat(d.r)

return d;
}

var rScale = d3.scaleLinear().domain([0, 10]).range([0, 50]);
var colorScale = d3.scaleLinear().domain([0, 10]).range(['red', 'blue']);
var svg = d3.select('body').append('svg')
.attr('width', 500)
.attr('height', 500)
.style('background-color', 'yellow');

d3.csv('data.csv', type, function(error, data) {
if ( error ) throw error;

render(data);
});

scale 메소드가 없다면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function render(data) {
var circle = svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', function(d) {
return d.r;
})
.attr('fill', 'red');
}

데이터의 값의 따라 크기를 무조건 정하면 첫번째의 경우는 아주 작은점으로 나타나고 좀 더 scale을 키워서 나타내기를 원할 것이다.
반대로 데이터값이 클경우 원의 크기가 svg 영역을 넘을 수도 있다는 것이다. 이때 scale 메소드를 이용하면 svg 영역 비율에 맞게 자동으로 scale 비율이 맞춰진다.

1
2
3
d3.scaleLinear()
.domain([최소값, 최대값])
.range([최소값, 최대값]);

기본 구조는 이렇게 생겼으며 domain(참조범위)이고 range(반환범위) 이다.
메서드의 동작은 시각화 할때 데이터밧은 domain()이고 그 값에 대해 반환되는 값이 range() 이다.

1
2
3
4
5
var scale = d3.scaleLinear().domain([0, 10]).range([0, 100]);

scale(2) => 20 반환
scale(5) => 50 반환
scale(10) => 100 반환

위 예제 코드 구문에서

1
2
var rScale = d3.scaleLinear().domain([0, 10]).range([0, 50]);
var colorScale = d3.scaleLinear().domain([0, 10]).range(['red', 'blue']);

rScale의 참조할 범위가 [010]이 되는데 여기서 반환범위가 [050]이 된다.
colorScale의 참조할 범위가 [0~10]이 되는데 반환범위가 [‘red’, ‘blue’]가 된다.
여기서 컬러의 반환범위가 숫자가 아니라 문자열이다. 이는 곧 컬러범위를 뜻하며 (R,G,B)가 있으면 (255,0,0) ~ (0,0,,255)까지의 범위가 된다.

1
2
3
4
5
6
var circle = svg.selectAll('circle')
...
.attr('r', function(d) {
return rScale(d.r);
})
...

데이터 d.r 의 값을 대입하면

  • rScale(1) => 5 반환
  • rScale(3) => 15 반환
  • rScale(5) => 25 반환
  • rScale(7) => 35 반환
  • rScale(9) => 45 반환
1
2
3
4
5
var circle = svg.selectAll('circle')
...
.attr('fill', function(d) {
return colorScale(d.r);
});

데이터 d.r 의 값을 대입하면

  • colorScale(1) => rgb(230,0,26) 반환
  • colorScale(3) => rgb(179,0,77) 반환
  • colorScale(5) => rgb(128,0,128) 반환
  • colorScale(7) => rgb(77,0,179) 반환
  • colorScale(9) => rgb(26,0,230) 반환

이렇게 반혼된 값들은 실제 읽어온 데이터의 값을 유지하면서 시각화 할대의 자동으로 크기나 색이 조절되게 만들 수 있다.
d3.scaleLinear() 메소드는 사실 두 값의 범위값으로 해서 반환범위값이 나오는 단순한 방식이다.

참고로 domain()의 들어가는 인자값들을 읽어온 데이터값을 기준으로 재정의 될 수 있고 range()의 반환값들도 좀 더 다양한 형태로 변경할 수 있다.

참조

공유하기