chart.js 코드 정리

MIT 라이선스인 chart.js를 예제를 통해 간단하게 정리해 봅니다. 구현하고자 하는 모습은 아래의 영상과 같습니다.

꺽은선 차트이며, 2개의 데이터 축을 가지고 1초마다 데이터가 변경됩니다.

먼저 DOM 구조입니다.

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div>
    <canvas id="chart"></canvas>
</div>

CSS는 다음과 같구요.

@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap');

body {
    margin: 0;
    padding: 0;
}

div {
    width: 600px;
    height: 400px;
    padding: 20px;
}

이제 JS 코드에 대한 내용인데, 먼저 차트를 위한 기본 골격은 다음과 같습니다.

Chart.defaults.font.family = 'Noto Sans KR';

const ctx = document.getElementById('chart');

const config = {
    // CORE PART !!
};

const chart = new Chart(ctx, config);

위의 config에 속성값을 지정함으로써 차트를 정의하는 세세한 내용을 결정할 수 있습니다. config에 대한 속성값은 다음과 같이 정의했습니다.

const config = {
    type: 'line',
    data: {
        labels: ['빨강', 'Blue', 'Yellow', '초록', 'Purple', '오렌지'],
        datasets: [
            {
                label: '변곡점1',
                data: [12, 19, 3, 5, 2, 3],
                backgroundColor: 'yellow',
                borderColor: 'black',
                borderWidth: 1
            },
            {
                label: '변곡점2',
                data: [10, 16, 7, 6, 4, 2],
                backgroundColor: 'white',
                borderColor: 'gray',
                borderWidth: 1
            }
        ]
    },
    options: {
        maintainAspectRatio: false,
        plugins: {
            title: {
                display: true,
                text: '차트, 그것이 알고 싶다.'
            }
        },
        scales: {
            x: {
                title: {
                    display: true,
                    text: '색상'
                }
            },
            y: {
                title: {
                    display: true,
                    text: '변곡량'
                }
            }
        },

    }
}

앞서 실행 화면을 보면 1초마다 차트의 값이 변경되는 것을 볼 수 있습니다. 이에 대한 코드는 다음과 같습니다.

setInterval(() => {
    const datasets = config.data.datasets;

    for (let iDataset = 0; iDataset < datasets.length; iDataset++) {
        const data = datasets[iDataset].data;
        for (let iValue = 0; iValue < data.length; iValue++) {
            data[iValue] += Math.random() * 2.0 - 1.0;
        }
    }

    chart.update();
}, 1000);

matplotlib에서 애니메이션 그래프 표현하기

matplotlib는 다양한 그래프를 표현할 수 있는데요. 정적인 그래프 뿐만 아니라 데이터가 실시간으로 변경되면 그에 대한 동적인 그래프도 표현할 수 있습니다. 아래는 예시로써 그 결과입니다.

위의 예시를 실제로 구현하기 위한 코드를 살펴 보겠습니다. 이를 위해 먼저 그래프로 표현하기 위한 데이터가 필요한데, 아래의 코드는 데이터를 구성하는 코드입니다.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

data = np.random.uniform(0, 1, (64, 75))
X = np.linspace(-1, 1, data.shape[-1])
G = 1.5 * np.exp(-4 * X ** 2)

예시의 결과를 보면, 65개의 꺽은선 그래프로 구성되어 있습니다. 아래는 이 꺽은선 그래프를 구성하는 코드입니다.

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(8, 8))
ax = plt.subplot(111, frameon=False)

lines = []
for i in range(data.shape[0]):
    xscale = 1 - i / 200.0
    lw = 1 - i / 100.0
    line, = ax.plot(xscale * X, i + G * data[i], color="k", lw=lw)
    lines.append(line)

이제 최종적으로 데이터를 0.2초마다 변경하고, 변경된 데이터에 대한 그래프를 업데이트하면서 마치 동적으로 그래프가 움직이는 효과를 내는 코드를 살펴 보겠습니다.

import matplotlib.animation as animation

ax.set_xticks([])
ax.set_yticks([])

ax.text(0.5, 1.0, "MATPLOTLIB ", transform=ax.transAxes, ha="right", va="bottom", color="k", 
        family="sans-serif", fontweight="bold", fontsize=16)
ax.text(0.5, 1.0, "DYNAMIC", transform=ax.transAxes, ha="left", va="bottom", color="k",
        family="sans-serif", fontweight="light", fontsize=20)

def update(*args):
    data[:, 1:] = data[:, :-1]
    data[:, 0] = np.random.uniform(0, 1, len(data))

    for i in range(len(data)):
        lines[i].set_ydata(i + G * data[i])

anim = animation.FuncAnimation(fig, update, interval=200)
plt.show()

웹에서 JavaScript만으로 데이터 압축하여 파일로 저장하기

몇 일전에 웹에서 자바스크립트만으로 압축 파일의 압축을 해제하는 내용을 정리했습니다. 해당 글은 아래와 같습니다.

Javascript 기반의 압축 라이브러리, jszip

이제는 다시 웹에서 사용자가 만든 어떤 데이터를 하나의 압축 파일로 만들 필요가 있어, 앞서 살펴본 압축 라이브러리를 이용해 바이너리 데이터와 텍스트 데이터를 각각 file.bin과 file.txt라는 파일명으로 하여 하나의 a.zip 파일로 압축한 후 사용자의 PC에 다운로드 하는 코드를 정리합니다.

먼저 압축하고자 하는 바이너리 데이터를 아래의 코드처럼 준비합니다.

let buffer = new ArrayBuffer(8);
let dataview = new DataView(buffer);

dataview.setInt32(0, 9438);
dataview.setFloat32(4, 3224.3224);

위의 데이터는 file.bin이라는 파일명으로 압축파일에 존재하도록 아래처럼 코드를 추가합니다.

let zip = new JSZip();
zip.file("file.bin", buffer);

앞서 언급했듯, 바이너리 뿐만 아니라 텍스트 파일도 압축 파일에 추가해 봅니다. 아래처럼요.

zip.file("file.txt", 'Hello한글Hi!');

이제 이렇게 압축된 내용을 a.zip 파일로 저장하는 코드는 다음과 같습니다.

let zipFileName = 'a.zip';
zip.generateAsync({ type: "blob" }).then(
    function (blob) {
        if (isIE()) {
            saveToFile_IE(zipFileName, blob);
        } else {
            saveToFile_Chrome(zipFileName, blob);
        }
    }
);

못보던 isIE와 saveToFile_IE, saveToFile_Chrome 함수가 보입니다. 이 놈들은 아래의 글을 참고하시면 파악할 수 있답니다.

웹에서 Javascript 만으로 텍스트 파일 생성

JavaScript로 Excel 파일 읽기

서버측의 기술없이 클라이언트 기술만으로 로컬에 저장된 엑셀 파일을 다룰 수 있는 라이브러리인 sheetjs에 대한 다양한 기능 중 엑셀 파일을 읽는 기능에 대한 JavaScript 코드를 정리해 봅니다.

이 라이브러리를 별도로 다운로드 받지 않고도 CDN을 통해 이용할 수 있습니다. 아래는 제가 이용한 CDN 접근입니다.


읽고자 하는 엑셀 파일은 다음과 같습니다.

위의 엑셀 파일을 선택하고, 선택된 엑셀 파일을 JSON 형식으로 변환해 콘솔에 출력하는 DOM 요소는 다음과 같습니다.


위의 input DOM 요소를 통해 파일을 선택할 때 발생하는 이벤트 코드는 다음과 같습니다.

function readExcel() {
    let input = event.target;
    let reader = new FileReader();

    reader.onload = function () {
        let data = reader.result;
        let workBook = XLSX.read(data, { type: 'binary' });

        workBook.SheetNames.forEach(function (sheetName) {
            console.log('SheetName: ' + sheetName);

            let rows = XLSX.utils.sheet_to_json(workBook.Sheets[sheetName]);
            console.log(JSON.stringify(rows));
        })
    };

    reader.readAsBinaryString(input.files[0]);
}

실행하고, 엑셀 파일을 선택해 보면 다음과 같은 내용이 콘솔에 표시되는 것을 확인할 수 있습니다.

SheetName: #인구수
[
   {
      "지역명":"무안군 무안읍",
      "남자":8599,
      "여자":7900,
      "가구수":6968,
      "노인수":732,
      "아저씨":1359,
      "어린이":4627
   },
   {
      "지역명":"무안군 일로읍",
      "남자":3659,
      "여자":3243,
      "가구수":3526,
      "노인수":8711,
      "아저씨":8758,
      "어린이":4099
   },

   ....

   {
      "지역명":"무안군 운남면",
      "남자":7357,
      "여자":7667,
      "가구수":3624,
      "노인수":8110,
      "아저씨":8042,
      "어린이":9618
   }
]

sheetjs 라이브러리는 엑셀을 읽는 기능 뿐만 아니라 생성도 가능하며 정교한 처리가 가능합니다.