본문 바로가기
BOOKS/수월한 자바스크립트

chart.js를 사용한 데이터 시각화하기 #1/3

by IT여행자 2024. 12. 26.
728x90


https://jobtc.tistory.com/146 (기본 차트)
https://jobtc.tistory.com/147 (실시간 차트)
https://jobtc.tistory.com/148 (서버 데이터 차트) 데이터 차트)

 

안녕하세요. IT여행자입니다. 

 

데이터를 시각화하는 방법에는 여러 가지 방법들이 있습니다. 사용하는 컴퓨터 언어나 서비스 환경에 따라 서로 다른 방법으로 데이터를 시각화합니다. 본 지면에서는 chart.js 라이브러리를 사용하는 방법을 사용해 보도록 하겠습니다. chart.js 라이브러리는 자바스크립트와 <canvas/> 태그를 사용하여 데이터를 시각화할 수 있는 도구 중 하나로 널리 알려져 있습니다.

chart.js 라이브러리를 사용한 데이터 시각화 과정은 아래의 몇 단계로 나누어 살펴보고자 합니다.

 

  • 기본 차트 그리기
    • 기본 차트
    • JSON 구조의 데이터를 차트로 그리기
    • 차트 제목, 범례 표시
    • 차트 종류
    • y축 지정
  • 실시간으로 차트 그리기
  • 서버와 연동하여 실시간으로 차트 그리기

준비물 1/3.

chart.js 라이브러리는 CDN 방식으로 라이브러리를 가져다 사용하도록 하겠습니다.

<script src="http://cdn.jsdelivr.net/npm/chart.js"></script>

 

준비물 2/3.

차트를 그리려면 앞서서 언급된 것처럼 <canvas/> 태그가 필요합니다. 이 태그를 자바스크립트에서 객체로 가져와 사용해야 합니다. 이 <canvas/> 태그의 크기는 차트를 그릴 때 옵션값으로도 지정할 수 있지만 코드의 단순함과 여러 가지 유연함을 위하여 <div/> 태그 안에 <canvas/>를 넣고 해당 <div/> 태그의 위치나 크기를 지정하는 방법으로 구성하도록 하겠습니다.

<style>
    #chart{
        width: 600px;
        height:500px;
        position : relative;
    }
</style>
...
<div id="chart">
    <canvas id="myChart"></canvas>
</div>

 

준비물 3/3.

데이터를 시각화하기 위해 차트를 그리려면 chart.js에서 제공한 Chart() 함수를 사용하게 됩니다. 기본 구조는 아래와 같이 작성됩니다.

var ctx = document.querySelector('#myChart').getContext('2d')
var myChart = new Chart(ctx, {옵션})

 

1) ctx

Chart() 함수를 사용하여 차트를 그리기 위해 사용되는 첫 번째 인수값입니다. 자바스크립트를 사용하여 <canvas/> 태그의 아이디 값을 사용하여 객체 ctx를 만들고 이를 첫 번째 인수값으로 사용합니다.

2) {옵션}

차트에 표시할 각종 데이터를 map 구조로 전달합니다. 보다 자세한 내용은 아래의 단계별 코드를 보면서 설명하도록 하겠습니다.

 

1. 기본 차트 그리기

차트를 그리기 위한 대부분의 값들이 준비되었으니 차트를 그려 봅시다. 차트를 그리기 위해 준비해야 할 데이터는 크게 3가지가 있습니다.

var xLabels = ['1월','2월','3월','4월','5월','6월']
var data = [10, 50, 30, 70, 90, 40]
var type = 'line'

 

1) xLables 

그래프의 x축에 표시될 데이터입니다. 

2) data

그래프를 그리기 위한 실제 값들입니다. 

3) type

그래프의 종류를 의미합니다.

 

Chart() 함수를 사용하여 그래프를 그릴 때 두 번째 인수값이 {옵션}이라 표현하였습니다. 이곳에 준비된 데이터들을 가져와 배치하면 됩니다. {옵션}에는 크게 data속성과 options속성이 있지만 기본 차트 그리기에서는 data 속성만을 사용하도록 하겠습니다.

var myChart = new Chart(ctx, {
    data: {
        labels : xLabels, /*x축 값 */
        datasets: [
            {
                data: data,
                type : type,
            }
        ]
    }
})

 

위의 코드를 살표 보면 data: 속성 안에 lables: 속성을 사용하여 x축의 값들을 지정합니다. 다음으로 datasets:속성이 있는데 이곳에 그려질 그래프의 개수에 따라 배열값으로 관련 속성들을 나열할 수 있습니다.  첫 번째로 그려질 그래프의 데이터값(data)과 그래프의 종류(type)가 지정되어 있습니다.

 

그럼 전체 코드와 그려진 그래프를 보도록 하겠습니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>chart step 1</title>
    <script src="http://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        #chart{
            width: 600px;
            height:500px;
            position : relative;
        }
    </style>
</head>

<body>
    <h3 class="info">기본 차트</h3>
    <div id="chart">
        <canvas id="myChart"></canvas>
    </div>
    <script>
        var ctx = document.querySelector('#myChart').getContext('2d')
        var xLabels = ['1월','2월','3월','4월','5월','6월']
        var data = [10, 50, 30, 70, 90, 40]
        var type = 'line'
        var myChart = new Chart(ctx, {
            data: {
                labels : xLabels,
                datasets: [
                    {
                        data: data,
                        type : type,
                    }
                ]
            }
        })
    </script>
</body>

</html>

 

2. JSON 구조의 데이터를 차트로 그리기

다양한 정보를 갖고 있는 데이터를 구조화하기 위해 JSON타입의 데이터를 구조를 많이 사용합니다. 그러나 데이터의 구조가 JSON으로 처리되어 있을 때 이를 chart.js가 사용하기 용이하도록 변경해야 할 필요가 있습니다. 이때 가장 유용하게 사용할 수 있는 방법 중에 하나로 map() 함수를 사용할 수 있습니다.

var data = [
    { month: '1월', amt: 10 },
    { month: '2월', amt: 50 },
    { month: '3월', amt: 30 },
    { month: '4월', amt: 70 },
    { month: '5월', amt: 90 },
    { month: '6월', amt: 40 },
]
var xLabels = data.map(d => d.month)
var amt = data.map(d => d.amt)

 

자바스크립트의 map() 함수를 사용하면 특정 데이터만을 추려서 새로운 배열을 만들 수 있습니다.

data.map(d=> d.month)는 data에 들어 있는 요소들을 하나씩 가져와 d에 담고 담은 d의 d.month부분만을 추려서 새로운 배열 xLables나 amt를 만들게 됩니다. 아래 코드와 그래프는 그래프 유형을 bar 타입으로 바꾸어 표시한 내용입니다.

 

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="http://cdn.jsdelivr.net/npm/chart.js"></script>
    <title>chart step 2</title>
    <style>
        #chart{
            width: 600px;
            height:500px;
            position : relative;
        }
    </style>

</head>

<body>
    <h3 class="info">
        데이터 구조가 JSON 구조 일 때
    </h3>
    <div id="chart">
        <canvas id="myChart" width="600" height="400"></canvas>
    </div>
    <script>
        var ctx = document.querySelector('#myChart').getContext('2d')
        var data = [
            { month: '1월', amt: 10 },
            { month: '2월', amt: 50 },
            { month: '3월', amt: 30 },
            { month: '4월', amt: 70 },
            { month: '5월', amt: 90 },
            { month: '6월', amt: 40 },
        ]
        var xLabels = data.map(d => d.month)
        var amt = data.map(d => d.amt)
        var type = 'bar'
        var myChart = new Chart(ctx, {
            data: {
                labels: xLabels,
                datasets: [
                    {
                        data: amt,
                        type: type,
                    }

                ]
            }
        })
    </script>
</body>

</html>

 

 

 

3. 차트 제목 및 범례 지정하기

이제 차트의 제목과 범례를 지정해 보도록 하겠습니다. Chart() 함수를 사용할 때 Chart(ctx, {옵션}) 과 같은 방법으로 사용하게 되는데, {옵션} 부분에 사용되는 대표적인 요소들이 data와 options 속성입니다. 비로소 지금 options부분에 값을 지정할 때가 되었습니다.

범례 개수를 3개로 만들기 위해 그래프를 그릴 때 3종류의 데이터값을 전달하도록 데이터를 아래와 같이 수정하였습니다.

var data = [
        {month:'1월', phone: 10, computer : 30, camera : 90},
        {month:'2월', phone: 50, computer : 30, camera : 120},
        {month:'3월', phone: 30, computer : 60, camera : 150},
        {month:'4월', phone: 70, computer : 90, camera : 60},
        {month:'5월', phone: 90, computer : 60, camera : 30},
        {month:'6월', phone: 40, computer : 70, camera : 90},
    ]

 

각 데이터마다 month는 x축의 값으로 사용하고, 나머지 phone, computer, camera 속성값들은 그래프에 사용될 데이터 값입니다. 또한 phone, computer, camara 자체는 범례에 표시할 문자열로 사용됩니다.

 

그래프를 3개 그려야 하기 때문에 datasets 속성에는 3개의 map 구조가 필요합니다.

datasets:[
  { 첫번째 그래프 속성들 },
  { 두번째 그래프 속성들 },
  { 세번째 그래프 속성들 }
]

 

3.1 범례

 

이 중에서 첫 번째 그래프 속성들만 좀 더 살펴보도록 하겠습니다.

datasets: [
    {
        label : Object.keys(data[0])[1], /* 첫번째 그래프의 범례 */
        data: data.map(d=>d.phone), /* 첫번째 그래프의 데이터 */
        type : 'bar', /* 첫번째 그래프 종류 */
        backgroundColor: '#0f0', /* 첫번째 그래프 색상 */
    },
    ...
]

 

1) label

각 블록에 있는 label 속성은 범례를 의미합니다. data [0]은 첫 번째 배열값을 의미하며, Object.keys(data [0])은 첫 번째 배열의 모든 키값들을 의미합니다. 즉 "month, phone, computer, camera"을 의미하겠지요. 이 데이터 값들에서 두 번째 키만을 가져오기 위해 Object.keys(data [0])[1]을 사용하게 되었습니다.

 

2) type

그려질 그래프의 종류를 막대그래프로 지정하였습니다.

 

3) backgroudColor

막대그래프의 바탕색을 지정합니다.

 

3.2 차트 제목

차트의 제목을 지정하기 위해서는 조금 복잡한 구조를 사용해야 합니다. 표시할 그래프에 대한 값들은 {옵션}에서 data: 속성을 사용하지만 그 외에 속성들은 options:에 기술합니다.

var title='월별 판매량'
...
options:{
    plugins:{
        title:{
            text : title, /* 제목 */
            display : true, /* 제목 표시 여부 */
            font : { /* 제목 문자열 속성 */
                size : 30,
                family : '맑은고딕',
                weight : 'bold'
            },
            color : '#00f' /* 제목 색상 */
        }
    }
}

 

구조가 조금 복잡해 보이는 것 빼고는  특별히 더 설명이 필요한 부분은 없을 것 같습니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="http://cdn.jsdelivr.net/npm/chart.js"></script>
    <title>chart step 2</title>
    <style>
        #chart{
            width: 600px;
            height:500px;
            position : relative;
        }
    </style>

</head>

<body>
    <h3 class="info">
        차트 제목, 그래프 제목 지정하기
    </h3>
    <div id="chart">
        <canvas id="myChart" width="600" height="400"></canvas>
    </div>
    <script>
        var ctx = document.querySelector('#myChart').getContext('2d')
        var data = [
                {month:'1월', phone: 10, computer : 30, camera : 90},
                {month:'2월', phone: 50, computer : 30, camera : 120},
                {month:'3월', phone: 30, computer : 60, camera : 150},
                {month:'4월', phone: 70, computer : 90, camera : 60},
                {month:'5월', phone: 90, computer : 60, camera : 30},
                {month:'6월', phone: 40, computer : 70, camera : 90},
            ]
        var title='월별 판매량'
        var myChart = new Chart(ctx, {
            data: {
                labels : data.map(d=> d.month),
                datasets: [
                    {
                        label : Object.keys(data[0])[1], /* 첫번째 그래프의 범례 */
                        data: data.map(d=>d.phone), /* 첫번째 그래프의 데이터 */
                        type : 'bar', /* 첫번째 그래프 종류 */
                        backgroundColor: '#0f0', /* 첫번째 그래프 색상 */
                    },
                    {
                        label : Object.keys(data[0])[2],
                        data: data.map(d=>d.computer),
                        type : 'bar',
                        backgroundColor: '#f00'
                    },
                    {
                        label : Object.keys(data[0])[3],
                        data: data.map(d=>d.camera),
                        type : 'bar',
                        backgroundColor: '#00f'

                    },
                ]
                },
                options:{
                    plugins:{
                        title:{
                            text : title, /* 제목 */
                            display : true, /* 제목 표시 여부 */
                            font : { /* 제목 문자열 속성 */
                                size : 30,
                                family : '맑은고딕',
                                weight : 'bold'
                            },
                            color : '#00f' /* 제목 색상 */
                        }
                    }
                }
        })

    </script>
</body>

</html>

 

datasets 안쪽을 자세히 보면 각 그래프별 그래프의 종류와 바탕색을 지정한 부분이 있을 것입니다. 

 

4. 차트 종류 바꾸어 보기

그래프를 그리기 위해 사용된 데이터와 옵션들은 동일하게 사용되었지만 bar, line, pie 그래프를 의미하는 3개의 버튼을 추가하였고, 해당 버튼이 클릭되면 그래프의 모양을 바꾸어 주는 코드를 추가하였습니다.

<button class="chartType" type="button">bar</button>
<button class="chartType" type="button">line</button>
<button class="chartType" type="button">pie</button>

3개 버튼이 모두 동일한 class명을 갖고 있고 문자열에 bar, line, pie를 갖고 있습니다. 3개의 버튼에 클릭이벤트를 추가하고 버튼이 클릭되면 버튼에 표시된 문자열을 사용하여 그래프의 종류를 바꾸고 해당 Chart() 함수로 만들어진 객체를 update()함으로써 차트의 종류가 서로 달라지도록 구성할 것입니다.

또한 그래프 각각의 그래프 모양을 바꾸려면 type속성을 datasets안에 기술하지만 전체 그래프의 모양을 한 번에 바꾸려면 옵션 최 상위 속성에 type 속성을 사용합니다.

 

버튼이 클릭되었을 때 이벤트 처리 부분입니다.

var chartType = document.querySelectorAll(".chartType");
chartType.forEach(btn =>{
    btn.addEventListener('click', (event)=>{
        myChart.config.type = btn.textContent;
        myChart.update();
    })
});

 

3개의 버튼에 모두 동일한 class명인 "chartType"을 지정하였으므로 이를 한 번에 가져오도록 document.querySelectorAll() 함수를 사용하였습니다. 이렇게 가져온 태그들을 forEach() 함수를 사용하여 순환하면서 click 이벤트를 추가하였습니다. 따라서 해당 버튼이 클릭되면 버튼이 갖고 있는 문자열인 btn.textContent 값을 myChart.config.type에 대입함으로써 그래프의 모양이 변경되는 것입니다. 이렇게 옵션값을 수정한 뒤 Chart()로 만들어진 객체를 업데이트하기 위해  myChart.update() 함수를 호출합니다.

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="http://cdn.jsdelivr.net/npm/chart.js"></script>
    <title>chart step 2</title>
    <style>
        #chart{
            width: 600px;
            height:500px;
            position : relative;
        }
    </style>

</head>

<body>
    <h3 class="info">
        차트의 종류 지정하기
    </h3>
    <div id="chart">
        <canvas id="myChart" width="600" height="400"></canvas>
    </div>

    <button class="chartType" type="button">bar</button>
    <button class="chartType" type="button">line</button>
    <button class="chartType" type="button">pie</button>
    <script>
        var ctx = document.querySelector('#myChart').getContext('2d')
        var data = [
                {month:'1월', phone: 10, computer : 30, camera : 90},
                {month:'2월', phone: 50, computer : 30, camera : 120},
                {month:'3월', phone: 30, computer : 60, camera : 150},
                {month:'4월', phone: 70, computer : 90, camera : 60},
                {month:'5월', phone: 90, computer : 60, camera : 30},
                {month:'6월', phone: 40, computer : 70, camera : 90},
            ]
        var title='월별 판매량'
        var type = 'line'
        var myChart = new Chart(ctx, {
            type : type,
            data: {
                labels : data.map(d=> d.month),
                datasets: [
                    {
                        label : Object.keys(data[0])[1],
                        data: data.map(d=>d.phone),
                        backgroundColor: '#0f0',
                    },
                    {
                        label : Object.keys(data[0])[2],
                        data: data.map(d=>d.computer),
                        backgroundColor: '#f00'
                    },
                    {
                        label : Object.keys(data[0])[3],
                        data: data.map(d=>d.camera),
                        backgroundColor: '#00f'

                    },
                    
                ]
            },
            options:{
                plugins:{
                    title:{
                        text : title,
                        display : true,
                        font : {
                            size : 30,
                            family : '맑은고딕',
                            weight : 'bold'
                        },
                        color : '#f00'
                    }
                }
            }
        })

        var chartType = document.querySelectorAll(".chartType");
        chartType.forEach(btn =>{
            btn.addEventListener('click', (event)=>{
                myChart.config.type = btn.textContent;
                myChart.update();
            })
        });

    </script>
</body>

</html>

 

 

 

5. y축 지정하기

y축의 값은 지정된 데이터에 의해 자동으로 설정되는 것이 Chart() 함수의 기본값입니다. 그러나 경우에 따라 임의로 저장할 필요가 있을 것입니다. 이 때는 options속성 안에서 scales속성을 사용합니다. 

options:{
    scales:{
        y:{
            min : 0,
            max : 200,
            ticks : {
                stepSize : 20
            }
        }
    }
}

 

y축의 최솟값(min), 최댓값(max)을 지정하였고 y축의 간격(stepSize)을 ticks 속성 안에 기술하면 됩니다. 

<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="http://cdn.jsdelivr.net/npm/chart.js"></script>
    <title>chart step 2</title>
    <style>
        #chart{
            width: 600px;
            height:400px;
            position : relative;
        }
    </style>
</head>

<body>
    <h3 class="info">
        y축 지정하기
    </h3>
    <div id="chart">
        <canvas id="myChart"></canvas>
    </div>
    <script>
        var ctx = document.querySelector('#myChart').getContext('2d')
        var data = [
                {month:'1월', phone: 10, computer : 30, camera : 90},
                {month:'2월', phone: 50, computer : 30, camera : 120},
                {month:'3월', phone: 30, computer : 60, camera : 150},
                {month:'4월', phone: 70, computer : 90, camera : 60},
                {month:'5월', phone: 90, computer : 60, camera : 30},
                {month:'6월', phone: 40, computer : 70, camera : 90},
            ]
        var title='월별 판매량'
       
        var myChart = new Chart(ctx, {
            data: {
                labels : data.map(d=> d.month),
                datasets: [
                    {
                        label : Object.keys(data[0])[1],
                        data: data.map(d=>d.phone),
                        type : 'bar',
                        backgroundColor: '#0f0',
                    },
                    {
                        label : Object.keys(data[0])[2],
                        data: data.map(d=>d.computer),
                        type : 'bar',
                        backgroundColor: '#f00'
                    },
                    {
                        label : Object.keys(data[0])[3],
                        data: data.map(d=>d.camera),
                        type : 'bar',
                        backgroundColor: '#00f'

                    },
                    
                ]
            },
            options:{
                scales:{
                    y:{
                        min : 0,
                        max : 200,
                        ticks : {
                            stepSize : 20
                        }
                    }
                }
            }
        })

    </script>
</body>

</html>

 

대부분의 코드는 반복됩니다. 필요에 의해서 생략된 경우도 있지만 크게 달라지지는 않았으리라 생각됩니다. 

 

다음 블로그엔 두 번째로 실시간으로 차트를 그리는 방법에 대해 알아보겠습니다.