D3_js

[D3.js] 막대 그래프 갱신, 트랜지션(trasition)

vhxpffltm 2019. 8. 28. 20:56

지금까지 정적인 테이터를 가지고 시각화를 하였다. 이제는 시각화에 변화를 통해 모션을 통해 트랜지션을 사용하여 시간에 따른 처리를 해보자

 

먼저 막대차트에 척도를 적용해보자.

1
2
3
4
5
 var xScale = d3.scaleBand()
                        .domain(d3.range(dataset.length))
                        .rangeRound([0, w])
                        .paddingInner(0.05);
        //rangeRoundd[0,w]는 0에서 시작해서 w로 끝나는 대역들을 계산해서 그 조각들을 치역으로 지정 
 

 

D3의 서열척도는 시각 요소를 같은 간격의 특정 순서로 위치시키려 할때에도 사용하여 그 코드는

.domain(d3.range(dataset.length)  이다.

 

range()를 통해 순서대로 값을 빠르게 생성할 수 있다. 파이썬의 range와 비슷하다고 생각하면 좋다. 즉 위 라인은 

dataset.length 로 데아터의 개수를 가지고 range()를 통해 [0~19]를 반환 후 domain()으로 반환된 배열로 새로운 서열 척도의 정의역을 지정한다.

 

이후의 코드는 치역의 대역폭을 정한다. 우리는 치역을 지정할 때, 모든 값을 직접 지정하는 range를 사용해도 되고 균등하게 알아서 분할하는 rangeRoundBand()를 사용할 수도 있다. 여기서는 rangeRound를 사용하여 해당 영역의 대역들을 계산해서 치역으로 지정하였다. 이것으로 막대 사이의 간격을 깔끔하게 적용할 수 있다.

 

이제 이 서열 척도를 참조하여 막대를 그려보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
svg.selectAll("rect")
           .data(dataset)
           .enter()
           .append("rect")
           .attr("x"function (d, i) {
               return xScale(i);
           })
           .attr("y"function (d) {
               return h - yScale(d);
           })
           .attr("width", xScale.bandwidth())
           .attr("height"function (d) {
               return yScale(d);
           })
           .attr("fill"function (d) {
               return "rgb(0, 0, " + Math.round(d * 10+ ")";
           });
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

xScale(i)을 호출하면서 서열 값 i를 보고, 그 순번에 맞는 치역값을 반환하다.  아래의 width와 height는 막대의 폭과 높이를 설정하는 것이다. bandwidth로 폭을 설정하였다. 이때까지의 작업을 보면 아래와 같다. 우리가 한 것은 어떤 데이터를 넣어도 시각화가 알아서 유연하게 조절이 가능하다. data값을 마음대로 수정해보아라.

 

 

 

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
var w = 600;
        var h = 350;
 
        var dataset = [5101319212522181513,
                        11121520181716182325];
 
 
        var xScale = d3.scaleBand()
                        .domain(d3.range(dataset.length))
                        .rangeRound([0, w])
                        .paddingInner(0.05);
 
        //rangeband[0,w]는 0에서 시작해서 w로 끝나는 대역들을 계산해서 그 조각들을 치역으로 지정 
 
 
        var yScale = d3.scaleLinear()
                        .domain([0d3.max(dataset)])
                        .range([0, h]);
 
 
        var svg = d3.select("body")
                    .append("svg")
                    .attr("width", w)
                    .attr("height", h);
 
 
        svg.selectAll("rect")
           .data(dataset)
           .enter()
           .append("rect")
           .attr("x"function (d, i) {
               return xScale(i);
           })
           .attr("y"function (d) {
               return h - yScale(d);
           })
           .attr("width", xScale.bandwidth())
           .attr("height"function (d) {
               return yScale(d);
           })
           .attr("fill"function (d) {
               return "rgb(0, 0, " + Math.round(d * 10+ ")";
           });
 
 
        svg.selectAll("text")
           .data(dataset)
           .enter()
           .append("text")
           .text(function (d) {
               return d;
           })
           .attr("text-anchor""middle")
           .attr("x"function (d, i) {
               return xScale(i) + xScale.bandwidth() / 2;
           })
           .attr("y"function (d) {
               return h - yScale(d) + 10;
           })
           .attr("font-family""sans-serif")
           .attr("font-size""11px")
           .attr("fill""white");
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 실행결과는 직접 확인해보길 바란다. 

우리는 순식간에 일어나는 이 시각화의 변화가 일어나는 것을 알아야 한다. 이번에는 새로운 데이터로 갱신되는 관련 코드를 다른 코드와 분리하여 페이지를 불러온 후 갱신하는 과정을 볼 것이다. 갱신의 시발점은 마우스 클릭으로 해보자.

 

html body에 <p> 태그를 사용하여 p태그에 이벤트 리스너를 추가한다. on 메서드를 사용하면 된다. 

 

1
2
3
d3.select('p').on("click"function () { 
  ....
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 
 
 

이제 위 스코프안에 코드를 작성할 것이다. 클릭이라는 이벤트가 발생하면 데이터를 새로 만들어 낼 것이다. 여기서는 임의로 값들을 바꾸었다. 이 후, svg.selectAll('rect').~~~~~로 새로 시각화를 갱신하면 된다. 데이터의 개수가 변하지 않았으므로 rect의 X축 좌표와 폭은 그대로 유지하고 Y축과 height만 갱신한다. 추가한 코드는 아래와 같다.

 
 
 
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
d3.select('p').on("click"function () {
        
            var len = dataset.length;
            dataset2 = [3,11,12,15,20,19,2,2,13,10,19,24,10,9,24,10,9,24,10,19];
 
            //클릭시, 데이터를 다른걸로 뒤집어쓴다.
            svg.selectAll('rect').data(dataset2)
            .attr('y'function (d) {
                return h - yScale(d);
            })
            .attr("height"function (d) {
                return yScale(d);
            })
            .attr('fill'function (d) {
                return 'rgb(0,0,' + Math.round(d * 10+ ')';
            });
            
            svg.selectAll('text').data(dataset2)
            .text(function(d){
                return d;
            })
            .attr('x'function (d, i) {
                return xScale(i) + xScale.bandwidth() / 2;
            })
            .attr('y'function (d) {
                return h - yScale(d) + 20;
            })
            .attr('class''ss');
        })
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
\

 

 

 

 

위 문구를 클릭하면 갱신된 값으로 시각화가 바뀐다. 이번에 이 변화에 트랜지션을 적용해 보고자 한다. D3에서 트랜지션은 .transition 만 추가하면 실행된다. 여기서 애니메이션의 기본 함수만 살펴보자.

 

transition() : d3는 시간 개념을 도입한다. attr()구문에 애니메이션을 적용

duration() : attr()이 변하는 기본값을 사용자가 정의할 수 있다. duration(1000) 은 1초이다.

ease() : 모션의 변동 비율이 일정하지 않고 가변적으로 사용할 때 사용, ()안에 bounce, cirlce 등의 내장함수를 넣어 적용 

delay : ease()와 다르게 트랜지션 시작 지점을 지정하여 밀리초로 정적인 값을 줄 수 있다. 

 

위의 4가지 정도의 트랜지션을 사용하여 아름다운 변화를 주었다. 그리고 위의 코드에서 데이터를 임의로 준 것이 아니라 랜덤한 값으로 줄 것이다. 데이터 변경은 후의 코드를 참조하자.

 

이제 마지막으로 하나만 갱신하면 된다. 혹시 해당 차트에서 데이터의 값이 25 이상인 값을 확인해 봤는가?? 우리는 새로운 데이터 값을 추가할 때마다, 막대가 너무 길거나 짧지 않도록 척도도 다시 갱신하야 한다.

 

척도는 y값만 갱신하면 되기 떄문에, yScale 변수를 새로 정의해준다. 치역을 저장하는 range()는 차트 크기가 변하지 않아 고정값이 들어있다. 새로운 데이터 셋을 생성하고 나면 domain()에서 척도의 정의역을 갱신해야 한다. 

이 한줄을 이용하여 dataset의 최대값을 사용하여 정의역 상한선의 값을 지정하도록 한다. 

 

여기까지 진행한 전체 코드와 결과를 확인해보자.

 

트랜지션의 값들을 변경하여 원하는 시각화를 시도해보고 데이터의 최대값 및 변화를 마음대로 조절하여도 제대로 시각화가 이루어지는지 확인하면 좋을 것 같다.

 

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
40
41
42
43
44
45
46
d3.select('p').on("click"function () {
        
            var len = dataset.length;
            dataset = [];
            var yMax = 200;
            for (var i = 0; i < len; i++) {
                var newnum = Math.floor(Math.random() * yMax);
                dataset.push(newnum);
            }
 
            yScale.domain([0d3.max(dataset)]);
            //척도를 갱신하여 y축의 최대값에 따라 차트를 그리도록 한다.,
            //dataset의 최대값을 이용해서 yscal 정의역 상한값을 지정한다.
 
            //클릭시, 데이터를 다른걸로 뒤집어쓴다.
            svg.selectAll('rect').data(dataset).transition().delay(function (i, d) {
                return i / dataset.length * 200;//딜레이가 가면 갈수록 더 지연되도록 함.
            }).duration(3000).ease(d3.easeBounceOut)
            .attr('y'function (d) {
                return h - yScale(d);
            })
            .attr("height"function (d) {
                return yScale(d);
            })
            .attr('fill'function (d) {
                return 'rgb(0,0,' + Math.round(d * 10+ ')';
            });
            //transtion을 통해 간단한 애니메이션 가능!!,duration은 지속시간
            //ease는 모션 변동 비율을 나타내면 위와같이 사용하고 항상 transition이 적용될 attr구문 사이에서 정의한다.
            //delay는 보통 duration전에 쓰며 지연을 의미, 여기서는 1초 후에 다음행동을 시작함 여기서는 텍스트가 먼저 변경되고 1초후 차트가 변경된다.
            //function을 사용하여 데이터의 색인값에 따라 갈수록 더 느려지게 조절함
            svg.selectAll('text').data(dataset).transition().delay(function (i, d) {
                return i /dataset.length * 200;
            }).duration(3000).ease(d3.easeBounce)
                .text(function (d) {
                    return d;
                })
            .attr('x'function (d, i) {
                return xScale(i) + xScale.bandwidth() / 2;
            })
            .attr('y'function (d) {
                return h - yScale(d) + 14;
            })
            .attr('class''ss');
            // 클릭시 위의 내용으로 전부 바뀐다, 
        })
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

'D3_js' 카테고리의 다른 글

[D3.js] 막대 추가해보기  (0) 2019.09.18
[D3.js] 산포도 갱신, 트랜지션  (0) 2019.08.28
[D3.js] 축_ aXis  (0) 2019.08.15
[D3.js] 척도  (0) 2019.08.03
[D3.js] Scatter_산포도  (0) 2019.07.25