프로필사진
owgno6
CODELIB
Recent Posts
Recent Comments
«   2024/11   »
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
Archives
Today
Total

티스토리 뷰


이번 장에서는 여러 데이터를 표현하는 기본적인 차트 중

다중곡선 차트에 대해 구성해본다.




그 중 예시로 연간 전기사용량(Electricity. kWh)에 대해서 

차트를 구성해본다.




[JSP]

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<!DOCTYPE html>
<meta charset="utf-8">
<style>

.axis--x path {
  display: none;
}

.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}
 
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
 
var svg = d3.select("svg"),
    margin = {top: 20, right: 80, bottom: 30, left: 50},
    width = svg.attr("width"- margin.left - margin.right,
    height = svg.attr("height"- margin.top - margin.bottom,
    g = svg.append("g")
    .attr("transform""translate(" + margin.left + "," + margin.top + ")");
 
var parseTime = d3.timeParse("%Y%m%d");
 
var x = d3.scaleTime().range([0, width]),
    y = d3.scaleLinear().range([height, 0]),
    z = d3.scaleOrdinal(d3.schemeCategory10);
 
var line = d3.line()
    .curve(d3.curveBasis)
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.electricity); });
 
d3.tsv("./js/02_data1.tsv", type, function(error, data) {
    if (error) throw error;
 
    var device = data.columns.slice(1).map(function(id) {
        return {
            id: id,
            values: data.map(function(d) {
                return {date: d.date, electricity: d[id]};
                })
            };
        });
 
    x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([
              d3.min(device, function(c) { return d3.min(c.values, function(d) { return d.electricity; }); }),
              d3.max(device, function(c) { return d3.max(c.values, function(d) { return d.electricity; }); })
              ]);
    z.domain(device.map(function(c) { return c.id; }));
 
    g.append("g")
        .attr("class""axis axis--x")
        .attr("transform""translate(0," + height + ")")
        .call(d3.axisBottom(x));
 
    g.append("g")
        .attr("class""axis axis--y")
        .call(d3.axisLeft(y))
        .append("text")
        .attr("transform""rotate(-90)")
        .attr("y"6)
        .attr("dy""0.71em")
        .attr("fill""#000")
        .text("Electricity, kWh");
 
    var etc = g.selectAll(".etc")
        .data(device)
        .enter().append("g")
        .attr("class""etc");
 
    etc.append("path")
        .attr("class""line")
        .attr("d"function(d) { return line(d.values); })
        .style("stroke"function(d) { return z(d.id); });
 
    etc.append("text")
        .datum(function(d) { return {id: d.id, value: d.values[d.values.length - 1]}; })
        .attr("transform"function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.electricity) + ")"; })
        .attr("x"3)
        .attr("dy""0.35em")
        .style("font""10px sans-serif")
        .text(function(d) { return d.id; });
    });
 
    function type(d, _, columns) {
        d.date = parseTime(d.date);
        for (var i = 1, n = columns.length, c; i < n; ++i) d[c = columns[i]] = +d[c];
        return d;
        }
 
</script>



[.TSV]

02_data1.tsv



[line 20 ~ 25]

d3.select로 svg(id 값)를 선택하고

그 밑에 margin과 width, height을 설정한다.

지금까지 여러차트를 만들면서 봤겠지만,

width와 height의 설정값이 대부분 비슷한 것을 알 수 있다.

margin의 크기를 상수로 정해주고, 그 크기만큼 svg의 크기에서 빼줌으로써

차트의 실질적인 가로크기와 세로크기를 지정해주기 때문.


다음은 'g' 요소로 svg를 그룹화한다.

사실 'g'는 위에서 지정한 svg 변수에 추가하여 svg를 그룹화 할 때 사용하므로

d3보다는 svg쪽에 가깝다.



[line 27] parseTime부분의 파싱에 대한 설명은 

전 장 예제에서 충분히 설명하였고,

[line 29 ~ 31]을 보면

기존 x축과 y축은 

어떤 단위로 어디까지(크기) 표현할 것인지를 각각 변수에 설정하는 것이고,

그리고 처음 보는 z축은 

데이터 시각화에 있어서 중요한 부분이다.

바로, 자동으로 각 선의 옵션을 설정해주는 것.

해당 옵션의 함수는 d3.schemeCategory10으로 하고

이 함수 카테고리에 대한 설명도 많이 다뤘으므로 패스.


[line 33 ~ 36]

d3.line 라인속성 설정과

curve의 부드러운선이 아닌 곡선이며,

x와 y에 대한 function은

그래프에 그려질 데이터를 설정하는 것이며

d는 enter()로 넣어진 데이터이고,

이는 데이터에 접근하기 위해서 콜백함수로 d를 다룹니다.



[line 38 ~ 48]

이미 tsv에 대한 자세한설명은 

전 장에서 예제를 다루며 했었지만

다시한번 복습차원에서 차근차근 해석해본다.


38
39
40
41
42
43
44
45
46
47
48
d3.tsv("./js/02_data1.tsv", type, function(error, data) {
    if (error) throw error;
 
    var device = data.columns.slice(1).map(function(id) {
        return {
            id: id,
            values: data.map(function(d) {
                return {date: d.date, electricity: d[id]};
                })
            };
        });



d3.tsv는 tsv파일을 가져오는 명령어의 d3함수이며

뒤의 "./js/02_data1.tsv"는 실제로 PC에 저장되어있는 파일명이며

현재 소스코드로부터 해당 파일의 경로를 나타낸 것입니다.

type의 설명은 전 장에 설명해서 넘어가고,

error(에러)와 data(tsv파일)는 해당 요소들을 다루기 위한 콜백함수다.



그리고 처음보는 함수인

data.columns.slice(1)는

컬럼(columns)의 데이터를 쌓는 역할을 한다.

slice(1)는 첫번째 데이터는 빼고 그 다음 데이터부터 쌓는 것을 의미한다.

따라서 date 부분인 날짜컬럼 영역 부분은 맵핑 되지 않고

다음 컬럼부터 맵핑된다.

아래 URL를 보면 이해하는데 도움이 된다.

Description reference to slice URL :

https://developer.mozilla.org/JavaScript/Reference/Array/slice



[line 50 ~ 55]

50
51
52
53
54
55
 x.domain(d3.extent(data, function(d) { return d.date; }));
    y.domain([
              d3.min(device, function(c) { return d3.min(c.values, function(d) { return d.electricity; }); }),
              d3.max(device, function(c) { return d3.max(c.values, function(d) { return d.electricity; }); })
              ]);
    z.domain(device.map(function(c) { return c.id; }));



아까 크기를 지정해준 x와 y를 직접 축으로 그려줍니다.

d3.extent는 데이터 중에서 최대 값과 최소 값을 찾아서 그 값으로 x축을 그려줍니다.

반면 y는 d3.min과 d3.max로 y축의 최소, 최대값을 찾아 일일이 지정해 줍니다.

그리고 z는 데이터들의 index(id)별로 전에 설정한 옵션(d3.schemeCategory10)을 매핑시켜줍니다.



[line 83]

데이터를 묶어주는 것은 datumdata가 있는데,

그 중 datum은 정적 데이터(업데이트가 없는)를 묶어주는 메소드입니다.

해당 영역(etc.append("text"))안에 든 데이터들을 id와 value에 묶어주는 역할을 합니다.

그리고 데이터를 좌표에 나타내기  위해 변형(transform)시킵니다.

x{d(데이터).value(매핑 시킨 data).date(그 중 날짜)}, y{d.value.electricity(해당 값)}으로

즉, ( x , y ) 모양으로 바꿔준 것.













다음은 tsv파일에 데이터를 더 추가해서 실행시켜본다.





데이터는 정해진 데이터가 없고

임의의 데이터인 난수이기 때문에 

난수 입력 데이터는 엑셀로 작업하면 쉽게 적용시킬 수 있다.





 =ROUND(RAND()*(M-N)+N,P)

 * M : 발생시키고자 하는 범위의 가장 큰 수

 * N : 발생시키고자 하는 가장 작은 수

 * P : 소수점 아래 자리 수

ex)  = ROUND(RAND()*(45-20)+20,1)

20 에서 45사이의 난수로서 소수점 아래 1자리까지 표시

 (20 과 45을 포함한 난수 발생)

















'D3.js' 카테고리의 다른 글

D3.js V4  (0) 2018.08.10
12 Real-Time Transition  (2) 2018.07.20
10 CSV(외부파일)로 차트(Chart) 구현  (0) 2018.06.25
09 TSV(외부파일)로 차트(Bar Chart) 구현  (1) 2018.06.21
07 원형 차트(Pie & Doughnut Chart)  (1) 2018.06.15
댓글