チャートって何だっけ？をコロナの感染者データと共に考えてみた

## はじめに
- React使っているのにチャート作れないとは言えない！という謎の気持ちになり、何かを題材に作ることにした
- 作っていくとそもそもチャートって何だっけ？と思い、気になって調べてまとめてみた

って感じで書いていきたいと思います。
時間ない人は、「[チャートを作成してみて](https://qiita.com/mball/items/90502ece54d6d168c6d1#%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%A6%E3%81%BF%E3%81%A6)」に今回の考察を記載したので、そちらをご覧いただければと思います。

## 見出し
- やること整理
- コロナの感染者データを使ってチャートを作ってみる
- チャートを作成してみて
- そもそもチャートとは
- ついでにチャートにどんな効果/適した用途があるのかそれぞれ調べてみた
- まとめ


## やること整理
コロナの感染者データを使ってチャートを作ってみることにしました。
今回は感染者数/死亡者数を時系列でまとめるために

- 棒グラフ
- 折れ線グラフ
- 時系列ヒートマップ

の3つを作っていきます。

### APIを選定する上で気をつけたこと
データをAPIを用いて取得してきます。複数あったので選定する上で気をつけたことは、

- 取得できるデータがチャートに合ったデータに生成できる形であること
    - 今回は
        - 時系列でまとめたいので日付ごとにデータをまとまっている（まとめることができる）
        - 感染者数と死亡者数を見たいのでそれぞれのデータが別々で取得できる
    - の二点が実現できる必要があります
- 無料であること
    - 学習用なのでみなさまの優しさに甘えます

と用途や要件に沿ったAPIを探しました。今回は以下のAPIを使用します。

https://covid19api.com/

### ライブラリを選定する上で気をつけたこと
チャートを１から作るのはしんどいので、ライブラリを探しました。たくさんあったのですが

- 作りたいチャートが作れる
    - 今回は
        - 棒グラフ
        - 折れ線グラフ
        - 時系列ヒートマップ
    - の3種類が作成できるライブラリが必要です
- メンテナンスがされている
    - メンテナンスされていないと、チャート作りたいのに作れない！ってなるかもしれないな、と思いました
- ドキュメントがわかりやすい
- お試しできる
    - 作れると分かっても、どんなイメージで仕上がるかの想像がつかないと少し怖かったので、ドキュメントやCodeSandboxですぐに試せるライブラリがあれば良さそうだなと思いました
- ライセンス
    - コードの開示義務があるとちょっと厄介なので、そこは避けるようにしました
    - ライセンスに関しては「[エンジニアが最低限理解しておくべきOSSライセンスの基礎知識](https://future-architect.github.io/articles/20200821/)」がわかりやすかったので載せておきます

といった点を見つつ選定しました。今回は [nivo](https://nivo.rocks/) を使うことにします。業務で利用するとなったらサイズやパフォーマンスなども意識しないといけないと思いますが、今回は無視します。
ちなみに似たライブラリをいくつか合ったので npm trend を使って比較しました。

https://www.npmtrends.com/@nivo/core-vs-react-apexcharts-vs-react-chartjs-2-vs-react-vis-vs-recharts-vs-victory

## コロナの感染者データを使ってチャートを作ってみる
前置き長くなりました。チャートを作っていきます。環境は React + TypeScript です。

### 型の生成
APIを用いて取得するのでまずは型情報を作ります。
Json形式で取得できるので、まずは一つ実データをjsonファイルに格納します。

```src/data/covidData.json
{
  "Country": "Japan",
  "CountryCode": "",
  "Province": "",
  "City": "",
  "CityCode": "",
  "Lat": "0",
  "Lon": "0",
  "Confirmed": 2,
  "Deaths": 0,
  "Recovered": 0,
  "Active": 2,
  "Date": "2020-01-22T00:00:00Z"
}
```

上記のJson形式のデータを元に型を生成します。

```src/types/covid.ts
import * as covidData from '../data/covidData.json';

export type CovidData = typeof covidData;
```

### データ取得
次にデータの取得ロジックを作ります。

```src/repositories/fetchCovidData.ts
import axios, { AxiosResponse } from 'axios';
import { CovidData } from '../types/covid';

const apiUrl = 'https://api.covid19api.com/total/country';

export const fetchCovidDataByCountry = async (
  country: string
): Promise<AxiosResponse<CovidData[]>> => {
  return axios.get<CovidData[]>(`${apiUrl}/${country}`);
};
```

### カスタムフック
チャートのコンポーネントファイルで定義したデータ取得の関数を呼び出すと記述量多くなってしまうのと、重複したロジックを書くことになるので、カスタムフック内で呼び出すことにします。

```src/features/charts/hooks/useCovidData.ts
import moment from 'moment';
import { useCallback, useEffect, useState } from 'react';
import { CovidData } from '../../../types/covid';
import { fetchCovidDataByCountry } from '../../../repositories/fetchCovidData';

export const useCovidData = (): { covidData: CovidData[] | undefined } => {
  const [covidData, setCovidData] = useState<CovidData[]>();

  const fetchData = useCallback(async () => {
    const data = await fetchCovidDataByCountry('japan');
    const sortedData = data.data.sort((a, b) => {
      const aMoment = moment(a.Date).valueOf();
      const bMoment = moment(b.Date).valueOf();
      return aMoment - bMoment;
    });
    setCovidData(sortedData);
  }, []);

  useEffect(() => {
    fetchData();
  }, []);

  return { covidData };
};

```

### グラフの作成
コードは長くなってしまうのと、ほとんどドキュメントのサンプル通りなので割愛します。代わりにURLを載せておきます。ここでは作成した結果を載せます。

- [棒グラフ](https://nivo.rocks/bar/)
- [折れ線グラフ](https://nivo.rocks/line/)
- [時系列ヒートマップ](https://nivo.rocks/calendar/)

#### 感染者数
![スクリーンショット 2022-01-23 17.20.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/afc5d7fe-431b-e1d3-525b-1bdccef2bfce.png)


#### 死亡者数
![スクリーンショット 2022-01-23 17.20.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/462620/8722194e-bc11-164f-9050-180ae6bdc0dc.png)

## チャートを作成してみて

- 棒グラフは、大小を比較するグラフとして用いられるが、時系列の変化を表現したい時も使用出来そう
- 感染者数と死亡者数の積み上げ棒グラフを作成してみたが、値が大きく異なったため尺度を同じにしてはいけないと感じた
    - 尺度を変えてあげれば良さそうなので、一つのグラフに二つの折れ線を用意して左は感染者数の尺度、右は死亡者数の尺度、としてあげるのが良さそう
- 折れ線グラフは、時系列の変化を表現する時に適切
- 折れ線グラフは、データの数によってはポイントの大きさに気をつけないと、ちょっと見づらくなる
- 時系列ヒートマップは、この時期感染者多かったんだな、などが感覚的にわかる
- 時系列ヒートマップは、プロパティに最大値をセットして、その値と比較して色が決まるため、最大値によって表示のされ方が変わってくる（与える印象が変わってくるから最大値は気を使う必要がありそう）
    - 尺度が感染者数と死亡者数で全然違うのに、見え方は同じだから誤解を生みやすい

と感じました。一番大事だと思ったのは **尺度をチャートを見るひとと認識を合わせること** です。

## そもそもチャートとは

> 情報の視覚的表示、図・表・グラフ等のこと
https://ja.wikipedia.org/wiki/%E3%83%81%E3%83%A3%E3%83%BC%E3%83%88

です。チャートの種類の一つにグラフがあるみたいです。（僕は一緒だと思ってました）

ちなみにグラフとは

> 互いに関係のある二つ以上の数量を図に描いたもの
https://wa3.i-3-i.info/word15583.html

でした。

## ついでにチャートにどんな効果/適した用途があるのかそれぞれ調べてみた

- **棒グラフ**
    - 棒の高さで、量の大小を比較する
    - 気をつけること
        - データを並べる順番(横軸)は規則的にする
            - データの多い/少ない順
            - 都道府県の場合は、北から
            - 時間軸の場合は時間順
        - 積み上げの棒グラフは、「全体としては増大傾向にあるが、ある領域は縮小している」といった傾向を伝えたい時に使用する

- **折れ線グラフ**
    - 量の変化を見る
    - 気をつけること
        - 複数のデータを一つのグラフに重ねるときは、区別をつける
            - 色
            - 実線や波線
        - 縦軸のメモリはゼロから
        - ただし、数字に変化が無くて見にくいときはときは、縦軸を省略する
- **円グラフ**
    - 全体の中での構成比を見る
    - 気をつけること
        - データは時計の針の 12 時の位置から大きい順に並べる
        - 「その他」はいくら大きくても、一番最後に表示する
        - あまり扇型が小さくなるとグラフが見にくくなるので、構成比が小さいものは、「その他」にまとめる
        - 「〇〇に賛成ですか」のような質問に対する回答を円グラフに表示する場合など、必ずしも他の大きい順に並べないこともある
- **帯グラフ**
    - 構成比を比較する
    - 気をつけること
        - 構成日を見ることが目的なので、棒の長さは全て同じにする
        - 項目を並べる順番を途中で変えない
- **レーダーチャート**
    - 複数の指標をまとめてみる
    - 気をつけること
        - データが大きいほど良い、となるようにデータを選ぶ
        - 50m 走などはタイムが短いほど良いので速度に直す、など
        - 5 段階評価に直す、などがよく行われる
- **散布図**
    - 2 種類のデータの相関を見る
    - 気をつけること
        - 相関関係があるかどうか、がわかるだけであり、因果関係を示すものではない
- **バブルチャート**
    - 3 種類のデータの関係性を見る
    - 気をつけること
        - 相関関係があるかどうか、がわかるだけであり、因果関係を示すものではない
- **時系列ヒートマップ**
    - 色の強弱をつけて、時系列に並べることで、時間の経過に伴う変化を表す
    - 気をつけること
        - 長期での全体像を感覚的に把握するために使用する

参考: https://www.center.shizuoka-c.ed.jp/files/24_jissenken_web/nougyou0314/5-4_0grafunosyuruitotokutyou.pdf
https://www.wingarc.com/product/motionboard/blog/graph_type.html
https://scrapmedia.meganii.com/%E6%99%82%E7%B3%BB%E5%88%97%E3%83%92%E3%83%BC%E3%83%88%E3%83%9E%E3%83%83%E3%83%97

## まとめ
チャートに関して今まであまり意識してきませんでしたが、データを可視化する上で使い方をよく考えなければ正しく情報を伝えることができないと気づきました。（間違った解釈をされてもそれは受け取る側の問題だろ、と突き放してはいけません）

情報は正しくても、正しく情報を伝えられなくては意味がない、ということが分かったので、もし今後チャートを使う際は、どう伝えれば正しく伝わるか、を意識していきたいと思います。

また、チャートのライブラリは充実しているので試しやすくてよかったです。
時間を作ってまた、違ったことにチャレンジしてみたいと思います。