Fitbitの期間を指定してデータを取得/可視化する

チュートリアル

こんにちは!今回は、Fitbitから期間を指定してデータを取得し、取得したデータを可視化する方法について解説します。Fitbitは、ウェアラブルデバイスやアプリを通じて健康関連のデータを収集・管理するプラットフォームです。この記事では、PythonとFitbit APIを使用して、指定した期間の心拍数データを取得し、そのデータをSeabornとMatplotlibを使ってグラフで可視化します。


こちらの記事もおすすめ

Fitbit APIの登録方法
Fitbit APIを使用すると、自分のアプリケーションからFitbitのユーザーデータにアクセスできるようになります。この記事では、初心者向けにFitbit APIの登録方法を詳しく解説します。こちらの記事もおすすめFitbit開発者アカ...
Fitbitで心拍数データを時系列で取得・可視化する方法
Fitbitは、ウェアラブルデバイスやアプリを通じて健康管理をサポートするプラットフォームです。本記事では、Fitbit APIを使用して心拍数データを取得し、時系列グラフで可視化する方法を初心者向けに解説します。こちらの記事もおすすめ前提...

前提条件

  • Fitbitアカウントを持っていること
  • Fitbit APIのアクセストークンを取得していること
  • PythonとGoogle Colabの基本的な知識があること

手順

1. 必要なライブラリのインポート

最初に、必要なライブラリをインポートします。requestsはHTTPリクエストを送るため、jsonはJSONデータを扱うため、datetimeは日付と時間を扱うために使用します。

import requests
import json
from datetime import datetime, timedelta

2. 設定ファイルの読み込みと保存

アクセストークンなどの設定情報をtoken.jsonファイルから読み込むための関数load_config()と、設定情報を保存するための関数save_config()を定義します。

CONFIG_FILE = "token.json"

def load_config():
    """設定ファイルを読み込む"""
    try:
        with open(CONFIG_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    except FileNotFoundError:
        print(f"設定ファイル {CONFIG_FILE} が見つかりません。")
        exit(1)

def save_config(config):
    """設定ファイルを保存する"""
    with open(CONFIG_FILE, "w", encoding="utf-8") as f:
        json.dump(config, f, indent=2)

3. 認証用のヘッダを作成

APIリクエストを送る際に必要な認証用のヘッダを作成する関数create_auth_header()を定義します。

def create_auth_header(access_token):
    """認証用のヘッダを作成する"""
    return {"Authorization": "Bearer " + access_token}

4. アクセストークンの更新

アクセストークンの有効期限が切れた場合に、リフレッシュトークンを使って新しいアクセストークンを取得する関数refresh_access_token()を定義します。

def refresh_access_token(config):
    """アクセストークンを更新する"""
    url = "https://api.fitbit.com/oauth2/token"
    params = {
        "grant_type": "refresh_token",
        "refresh_token": config["refresh_token"],
        "client_id": config["client_id"],
    }

    response = requests.post(url, data=params)
    data = response.json()

    if "errors" in data:
        print(f"アクセストークンの更新に失敗しました: {data['errors'][0]['message']}")
        return False

    config["access_token"] = data["access_token"]
    config["refresh_token"] = data["refresh_token"]
    save_config(config)
    return True

5. アクセストークンの有効期限のチェック

APIレスポンスからアクセストークンの有効期限が切れているかどうかをチェックする関数is_token_expired()を定義します。

def is_token_expired(response_data):
    """アクセストークンの有効期限が切れているかチェックする"""
    if "errors" in response_data:
        for error in response_data["errors"]:
            if error.get("errorType") == "expired_token":
                print("アクセストークンの有効期限が切れています。")
                return True
    return False

6. APIリクエストの実行

APIリクエストを実行する関数make_api_request()を定義します。アクセストークンの有効期限が切れている場合は、refresh_access_token()関数を呼び出して新しいアクセストークンを取得します。

def make_api_request(url, headers):
    """APIリクエストを実行する"""
    response = requests.get(url, headers=headers)
    data = response.json()

    if is_token_expired(data):
        config = load_config()
        if refresh_access_token(config):
            headers = create_auth_header(config["access_token"])
            response = requests.get(url, headers=headers)
        else:
            print("アクセストークンの更新に失敗したため、リクエストを中止します。")
            exit(1)

    return response

7. 心拍数データの取得

指定した期間の心拍数データを取得する関数get_heart_rate()を定義します。開始日と終了日の妥当性をチェックし、最大期間が1年以内であることを確認します。

def get_heart_rate(start_date="today", end_date="today"):
    """心拍数データを取得する"""
    config = load_config()
    headers = create_auth_header(config["access_token"])

    # 日付の妥当性をチェック
    if start_date == "today":
        start_date = datetime.now().strftime("%Y-%m-%d")
    if end_date == "today":
        end_date = datetime.now().strftime("%Y-%m-%d")

    start_date_obj = datetime.strptime(start_date, "%Y-%m-%d")
    end_date_obj = datetime.strptime(end_date, "%Y-%m-%d")

    if start_date_obj > end_date_obj:
        raise ValueError("start_date must be earlier than or equal to end_date")

    if (end_date_obj - start_date_obj).days > 365:
        raise ValueError("Maximum range is 1 year")

    url = f"https://api.fitbit.com/1/user/-/activities/heart/date/{start_date}/{end_date}.json"
    return make_api_request(url, headers)

[
  {
    "dateTime": "2024-03-01",
    "value": {
      "customHeartRateZones": [],
      "heartRateZones": [
        {
          "caloriesOut": 2561.7088,
          "max": 115,
          "min": 30,
          "minutes": 1423,
          "name": "Out of Range"
        },
        {
          "caloriesOut": 112.19400000000002,
          "max": 140,
          "min": 115,
          "minutes": 16,
          "name": "Fat Burn"
        },
        {
          "caloriesOut": 8.0216,
          "max": 172,
          "min": 140,
          "minutes": 1,
          "name": "Cardio"
        },
        {
          "caloriesOut": 0,
          "max": 220,
          "min": 172,
          "minutes": 0,
          "name": "Peak"
        }
      ],
      "restingHeartRate": 64
    }
  },

8. データの取得と可視化

get_heart_rate()関数を呼び出して指定した期間の心拍数データを取得し、取得したデータをDataFrameに変換します。その後、Seabornを使ってデータを可視化します。

if __name__ == "__main__":
    response = get_heart_rate(start_date="2024-03-01", end_date="today")
    _data = response.json()
    data = _data["activities-heart"]

    # データをDataFrameに変換
    df = pd.DataFrame([
        {
            'dateTime': d['dateTime'],
            'name': z['name'],
            'caloriesOut': z['caloriesOut'],
            'max': z['max'],
            'min': z['min'],
            'minutes': z['minutes']
        }
        for d in data
        for z in d['value']['heartRateZones']
    ])

    # DateTimeをパースし、indexに設定
    df['dateTime'] = pd.to_datetime(df['dateTime'])
    df.set_index('dateTime', inplace=True)

    # カラーマップの定義
    color_map = {
        'Out of Range': 'gray',
        'Fat Burn': 'green',
        'Cardio': 'orange',
        'Peak': 'red'
    }

    # Out of Rangeの折れ線グラフ
    plt.figure(figsize=(10, 6))
    out_of_range_df = df[df['name'] == 'Out of Range']
    sns.lineplot(data=out_of_range_df, x=out_of_range_df.index, y='caloriesOut', label='Out of Range', color=color_map['Out of Range'])
    plt.title('Out of Range Calories Out Line Graph')
    plt.xlabel('Date')
    plt.ylabel('Calories Out')
    plt.xticks(rotation=45)
    plt.legend()
    plt.tight_layout()
    plt.show()

    # Fat Burn, Cardio, PeakのcaloriesOutの折れ線グラフ
    plt.figure(figsize=(10, 6))
    for name, group in df[df['name'] != 'Out of Range'].groupby('name'):
        sns.lineplot(data=group, x=group.index, y='caloriesOut', label=name, color=color_map[name])
    plt.title('Fat Burn, Cardio, Peak Calories Out Line Graph')
    plt.xlabel('Date')
    plt.ylabel('Calories Out')
    plt.xticks(rotation=45)
    plt.legend()
    plt.tight_layout()
    plt.show()

    # Out of Rangeのmin とMaxのキャンドルチャート
    plt.figure(figsize=(10, 6))
    sns.boxplot(data=out_of_range_df, x=out_of_range_df.index, y='max', color=color_map['Out of Range'])
    plt.title('Out of Range Heart Rate Zones Candlestick Chart')
    plt.xlabel('Date')
    plt.ylabel('Heart Rate')
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.show()

    # Fat Burn, Cardio, Peakのmin とMaxのキャンドルチャート
    plt.figure(figsize=(10, 6))
    for name, group in df[df['name'] != 'Out of Range'].groupby('name'):
        sns.boxplot(data=group, x=group.index, y='max', color=color_map[name])
    plt.title('Fat Burn, Cardio, Peak Heart Rate Zones Candlestick Chart')
    plt.xlabel('Date')
    plt.ylabel('Heart Rate')
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.show()

    # Out of Rangeのminutesの折れ線グラフ
    plt.figure(figsize=(10, 6))
    sns.lineplot(data=out_of_range_df, x=out_of_range_df.index, y='minutes', label='Out of Range', color=color_map['Out of Range'])
    plt.title('Out of Range Minutes Line Graph')
    plt.xlabel('Date')
    plt.ylabel('Minutes')
    plt.xticks(rotation=45)
    plt.legend()
    plt.tight_layout()
    plt.show()

    # Fat Burn, Cardio, Peakのminutesの折れ線グラフ
    plt.figure(figsize=(10, 6))
    for name, group in df[df['name'] != 'Out of Range'].groupby('name'):
        sns.lineplot(data=group, x=group.index, y='minutes', label=name, color=color_map[name])
    plt.title('Fat Burn, Cardio, Peak Minutes Line Graph')
    plt.xlabel('Date')
    plt.ylabel('Minutes')
    plt.xticks(rotation=45)
    plt.legend()
    plt.tight_layout()
    plt.show()

このコードでは、以下のグラフを生成します。

  1. Out of Rangeのカロリー消費量の折れ線グラフ
  2. Fat Burn、Cardio、Peakのカロリー消費量の折れ線グラフ
  3. Out of Rangeの心拍数のキャンドルチャート
  4. Fat Burn、Cardio、Peakの心拍数のキャンドルチャート
  5. Out of Rangeの時間の折れ線グラフ
  6. Fat Burn、Cardio、Peakの時間の折れ線グラフ

まとめ

この記事では、Fitbit APIを使用してPythonで指定した期間の心拍数データを取得し、取得したデータをSeabornとMatplotlibを使ってグラフで可視化する方法を解説しました。アクセストークンの管理、APIリクエストの実行、データの取得と可視化の手順を順を追って説明しました。

これらの手順を応用することで、他のFitbitデータも取得し、可視化することができます。健康管理や運動管理に役立てていただければ幸いです。

Googleコラボのノートブックはこちらからアクセスできます。

健康的な生活を送るためにFitbitデータを活用し、楽しくデータ分析を行ってください!

ノートブック

Google Colaboratory

リポジトリ

GitHub - Sunwood-ai-labs/fitbit-python-analyzer
Contribute to Sunwood-ai-labs/fitbit-python-analyzer development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました