matplotlibを使ったグラフ作成におけるグラフの選択について

## はじめに
研究を行うにあたって人間の歩数のデータを分析することになり，時間帯ごとの歩数データを可視化のためにいくつかグラフを作成しました．
その際，グラフの種類の選択について学びがあったので，研究内容とは直接関係はないですが共有します．



## matplotlibとは
Pythonのライブラリです．グラフ描画ができます．
描画できるグラフも折れ線グラフ，棒グラフ，ヒストグラムと様々あります．
今回作成したのはシンプルな折れ線グラフです．

### matplotlibの使い方
インストール方法は以下の通りです．
※Pythonがインストールされている状態で実行

```bash
pip install matplotlib
```

## 実行環境
この記事は以下の環境で動作確認しています：

- OS: Windows 11
- Python: 3.8.10
- matplotlib: 3.7.5

## 作ってみる
作成する際には，グラフ作成の対象となるデータが必要です．
この記事では，iPhoneのヘルスケアというアプリから歩数データをエクスポートしたXMLファイルを対象としています．

### 対象の1日のデータをグラフ化してみる
あの日はどのくらい歩いたかな......というのをグラフ化してみます．
つまり，対象の1日の歩数のデータを時間帯ごとにプロットします．
例として私が12月7日に，どの時間帯にどのくらい歩いたのかグラフ化してみました．
使用したコードはこちらです．


```python:step_make_graph_oneday.py
import xml.etree.ElementTree as ET
import matplotlib
import matplotlib.pyplot as plt
from datetime import datetime


#記述部
file_path = 'XXX.xml'  # xmlファイルのパス
target_date = '2024-12-07'  # グラフが欲しい日付（YYYY-MM-DD）
export_file_name = f'{target_date}_step_count.png' # 出力ファイルのパス＆ファイル名


# 歩数をカウントする関数
def step_count(xml_file, target_date_str):
    tree = ET.parse(xml_file)
    root = tree.getroot()

    target_date = datetime.strptime(target_date_str, "%Y-%m-%d")
    ten_minutely_steps = [0] * 144

    for record in root.findall('Record'):
        if record.get('type') == 'HKQuantityTypeIdentifierStepCount':
            start_date = record.get('startDate')
            value = int(record.get('value'))
            
            start_date_dt = datetime.strptime(start_date, "%Y-%m-%d %H:%M:%S %z")

            if start_date_dt.date() == target_date.date():
                hour = start_date_dt.hour
                minute = start_date_dt.minute

                # 粒度10分
                ten_min_index = hour * 6 + (minute // 10)
                ten_minutely_steps[ten_min_index] += value

    return ten_minutely_steps


# グラフを作成する関数
def plot_step_graph(ten_minutely_steps, target_date_str, save_path):

    time_labels = [f"{h}:00" for h in range(24)]
    
    plt.figure(figsize=(12, 6))
    plt.plot(range(144), ten_minutely_steps)
    plt.xlabel('time')
    plt.ylabel('step')
    plt.title(f'{target_date_str} step')
    plt.xticks(range(0, 144, 6), time_labels, rotation=90)

    plt.xlim(0, 144)
    plt.ylim(0, 2000)

    plt.grid(True, axis='y')

    plt.tight_layout()
    plt.savefig(save_path)
    plt.close()


# 関数の実行
ten_minutely_steps = step_count(file_path, target_date)
plot_step_graph(ten_minutely_steps, target_date, export_file_name)

```



そして，出力されたグラフがこちら

<img width="95%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3845425/3f791a73-d77d-149f-6ee8-b813ed572444.png">


簡単にグラフが作成できました．10分ごとにプロットされています．
この日は8：00過ぎと14：00頃，19：00前に歩数のトレンドがあるみたいです．



### ヘルスケアアプリ内のグラフを見てみる
このままではiPhoneのアプリであるヘルスケア内で歩数のグラフ見ているのと何も変わりません．データをエクスポートしたり，コードを実行したりしなくていい分ヘルスケアでグラフを見る方がマシです．
何か相違点があるといいのですが，，，

ヘルスケアで同じ日(12月7日)のグラフを見てみるとこんな感じです．


<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3845425/1300521b-71cf-3533-0cbb-9dbc6491ec55.png">



## 使うべきグラフの種類の選択
2つのグラフのぱっと見の相違点は，グラフの種類でしょうか．私が作ったグラフは折れ線グラフで，ヘルスケアアプリで確認できるグラフは棒グラフで作成されています．
私は歩数のグラフは折れ線グラフで作成すべきという教えを受け，折れ線グラフを作成しました．しかし，データのエクスポート元であるヘルスケアアプリを確認したら棒グラフでプロットされていて，困惑してしまいました．


### 歩数のデータでグラフを作成する際は，どんなグラフを使うのが適切なのか？
こんなこともあり，グラフの選択というグラフ作成における初歩的なことで悩みました．
データの中身によってはどのグラフを使うべきか正解がはっきり決まっているものもあります．例えば，日本の人口を他国の人口と比較したいのであれば国別に棒グラフを作成すべきですし，日本の人口の推移を確認したいのであれば年ごとにプロットした折れ線グラフを作成すべきです．
歩数のデータはどちらに該当するのでしょうか？

### 当たり前の結論にたどり着く
**このグラフで何を示したいか**によって適切なグラフが変わります．
歩数のデータをグラフ化する際は，折れ線グラフ，棒グラフ，どちらのグラフを使っても間違いではありません．このグラフで、何を伝えようとしているか？によってどちらを使うか選択することになります．
「1日の中の時間経過による歩数の推移や歩数のトレンドを可視化したい」のであれば折れ線グラフを，「1日の中の歩数を時間帯別に示したい」のであれば棒グラフを選択するのが適切です.
私が作成したグラフは時間経過による推移に注目して歩数のデータを示していて，ヘルスケアアプリのグラフは時間帯別の歩数を推移には注目せず示していた，ということです．


## おわりに
研究とは関係ないですが，グラフ作成について当たり前に理解していると思っていたことが理解できていなかったことに気づかされました．今回のように，適切なグラフが1つに定まらないデータもあります．どのグラフを選択するのが適切か迷ったら，そのデータを用いて自分が示したいことは何なのか？に注目して選択してください．