오늘은 D3.js 예제 중 Dount Chart 이미지가 너무 맘에 들어서 이미지를 보고 한번 비슷한 형태로 출력 해보는 실험이 하고 싶어서 도전을 해보았습니다. 이미지만 보고 코딩을 한 뒤에 출력 이미지의 Chart 형태를 어떤 원리가 숨어 있는지 살펴보고 다시 표현을 해보았습니다.
위 출처에 가시면 아래와 같은 시각화 차트가 만들어져서 동작하게 되더군요.
Dount Chart가 재밌는 형태로 출력이 되는데 정지 이미지로 어떤지 살펴 볼까요.
위 이미지를 보는 것 처럼 2개의 Donut Chart가 형성 되어 움직이는 Chart입니다. 그럼 이 2개의 Donut Chart은 어떻게 만들어지는지 연구해 보았습니다.
2개의 Donut Chart은 어떻게 만들어 질까요.
여기서,
var arc = d3.arc()
.innerRadius(50)
.outerRadius(200)
안쪽원과 바깥족 원의 길이를 설정하는데 위의 2개의 Dount Chart를 만들어내는 방식을 보면 홀짝으로 나누어서 홀이 고정 위치이면 짝은 바깥으로 나가거나 아니면 안쪽으로 들어가거나 둘 중 하나입니다.
innerRadius(), outerRadius()가 데이터 값에 따라 그려지는 위치를 홀짝으로 나누어 출력되게 하면 2개의 Donut Chart가 만들어 지겠죠.
이렇게 하면 Pie 조각 Chart가 교대로 홀짝으로 나뉘어서 안쪽 Pie조각, 바깥쪽 Pie조각으로 출력 되게 하면 원하는 Chart가 만들어 집니다.
순간 떠오르는 생각으로 간단히 표현 해보았습니다.
var arc = d3.arc()
.innerRadius(function (d,i) { if(i%2==0) return 50;
else return 100;})
.outerRadius(function (d,i) { if(i%2==0) return 100;
else return 200;})
그러면 한번 출력 해볼까요. 기본 소스는 참조에 있는 post의 소스를 기준으로 작성해 봤네요. sort(null)함수를 수행 안하면 자동으로 정렬 되어서 홀짝이 제대로 표현 안되어서 삽입했네요.
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
var data = [10, 20, 30, 40, 50, 60];
var arcs = d3.pie().sort(null)(data);
var width = 500;
var height = 500;
var arc = d3.arc()
.innerRadius(function (d,i) { if(i%2==0) return 50;
else return 100;})
.outerRadius(function (d,i) { if(i%2==0) return 100;
else return 200;})
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height)
g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height/ 2 +")")
var pie = g.selectAll("path")
.data(arcs)
.enter()
.append("path")
.style("fill", function(d){
return d3.color("hsl(100, 100%, " + d.value + "%)");
})
.attr("d", arc)
</script>
</body>
위 소스는 해당 참고 post를 읽도 정리하면 됩니다.
[결과]
좀 비슷해 졌네요.
.
단지 2개의 Donut Chart를 만든 다면 재미 없겠죠. 비슷하게 하려면 이 실험을 하게 된 동기인 Mike Bostock’s Block(출처 https://bl.ocks.org/mbostock/4341417)의 소스를 살펴보니 d3.range(n).map(Math.random) 코딩이 있는데 이 코딩을 인용합니다. 인용이라고 할 것 없이 Math.random을 이용하면 다양한 랜덤 데이터를 만들 수 있는데 표현이 같기 때문에 인용으로 post로 작성합니다.
데이터를 랜덤 데이터로 하기 위해서는 난수를 사용합니다.
var data = d3.range(6).map(Math.random);
이렇게 하면 6개의 난수를 만들어 내게 됩니다. 이 표현은 실험에 사용한 코딩의 일부분입니다.
실시간 데이터 갱신 : 다음과 같이 실시간으로 데이터를 만들어 내어 실행 시킬 수 있습니다.
function update(){
data = d3.range(6).map(Math.random);
render();
}
setInterval(update,1000);
이제 종합해서 기존 소스에 삽입을 하면 다음과 같습니다.
[전체소스]
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
//var data = [10, 20, 30, 40, 50, 60];
var data = d3.range(6).map(Math.random);
var arcs = d3.pie().sort(null);
var width = 500;
var height = 500;
var arc = d3.arc()
.innerRadius(function (d,i) { if(i%2==0) return 50;
else return 100;})
.outerRadius(function (d,i) { if(i%2==0) return 100;
else return 200;})
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height)
g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height/ 2 +")")
function render(){
var pie = g.selectAll("path")
.data(arcs(data0))
.style("fill", function(d,i){
return d3.color("hsl("+(d.value*100)%100+",100%,"+ (d.value*100)%100 + "%)");
})
.attr("d", arc)
.enter()
.append("path")
.style("fill", function(d,i){
return d3.color("hsl("+(d.value*100)%100+",100%,"+ (d.value*100)%100 + "%)");
})
.attr("d", arc)
}
function update(){
data0 = d3.range(6).map(Math.random);
render();
}
setInterval(update,1000);
</script>
</body>
이렇게 하면 1초 단위로 데이터는 갱신이 일어납니다.
참고로 hsl()함수 부분은 색을 랜덤으로 만드는 부분인데 좀 수정해 봤습니다.
[결과]
뭔가 움직이는 애니메이션 효과는 없지만 그럭저럭 비슷하게 표현 되었네요.
오늘의 내용은 Pie()함수를 이용하여 실험하고 싶은 Donut Chart 형태로 만들어 보았습니다. 그리고 나서 출처에 나온 예제를 어느정도 분석 한뒤에 최대한 느낌만 유사하게 표현을 했고요.
D3.js 예제들이 무지 많으니깐 여러분들도 이렇게 저처럼 그림만 보고 한번 상상력을 동원해서 코딩해보고 다시 소스를 보고 인용할 부분이 있으면 자신의 것으로 만들어 적용하는 실험을 해보세요. 이런게 쌓이면 나중에 멋지 시각화 차트를 만들지 않을까 생각 됩니다.