Loading [MathJax]/extensions/tex2jax.js

[fitbit] 7.Fitbit APIで一年分の睡眠時間を取得してヒストグラムで表示

fitbit

はじめに

fitbitとは、心拍数、歩数や睡眠をトラッキングするために腕に着用するタイプのスマートウォッチです。ここでは、Fitbit APIを使って一年分の睡眠時間を取得し、matplotlibのヒストグラムにより表示する方法を解説します。

手順

APIの登録など

その1を参照してください。

[fitbit] 1. PythonでFitbit APIを使ってデータ取得 その1 アプリの登録とtokenの取得
fitbitとは、心拍数、歩数や睡眠をトラッキングするために腕に着用するタイプのスマートウォッチです。日々の健康状態を把握するのにとても役立っています。ここでは、Fitbit APIを使ってデータを取得するために、アプリの登録からtokenの取得まで解説します。

fitbit-pythonのインストールなど

その2を参照してください。

[fitbit] 2. PythonでFitbit APIを使ってデータ取得 その2 fitbit-pythonによる睡眠データの取得とmatplotlibによる表示
fitbitとは、心拍数、歩数や睡眠をトラッキングするために腕に着用するタイプのスマートウォッチです。日々の健康状態を把握するのにとても役立っています。ここでは、アプリの登録からtokenの取得までを解説したその1の続きとして、Fitbit APIを使って睡眠データを取得してmatplotlibで表示するところまで解説します。

モジュールのインポートなど

import fitbit
from ast import literal_eval
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
import seaborn as sns
import datetime as dt
plt.style.use('ggplot')

バージョン

#version
import matplotlib
print(matplotlib.__version__)
3.4.2
print(fitbit.__version__)
0.3.1
print(pd.__version__)
1.2.4
print(np.__version__)
1.20.3
print(sns.__version__)
0.11.1

APIの認証

CLIENT_ID, tokenなどを定義

CLIENT_ID = "#####"
CLIENT_SECRET = "################"
TOKEN_FILE = "token.txt"
tokens = open(TOKEN_FILE).read()
token_dict = literal_eval(tokens)
access_token = token_dict['access_token']
refresh_token = token_dict['refresh_token']

その1で取得したCLIENT_IDとCLIENT_SECRETとtoken.txtをここで使います。token.txtは実行ファイルと同じ場所に置いておきます。

認証

def updateToken(token):
f = open(TOKEN_FILE, 'w')
f.write(str(token))
f.close()
return
client = fitbit.Fitbit(CLIENT_ID, CLIENT_SECRET,
access_token = access_token, refresh_token = refresh_token, refresh_cb = updateToken)

fitbit.Fitbit()により、認証を行います。updateToken関数はtokenの更新用の関数でrefresh_cbupdateTokenとすることでtokenが期限切れの際に随時更新してくれるようになります。

1年分のデータの取得

日付の設定

#日付の設定
DATE_s = "2020-01-01"
DATE_e = "2020-12-31"
DATE_s = dt.datetime.strptime(DATE_s, '%Y-%m-%d')
DATE_e = dt.datetime.strptime(DATE_e, '%Y-%m-%d')

2020年の最初と最後の日をそれぞれdatetime形式で作成します。

100 日間ごとに日付範囲を分ける

一度に取得することのできる日数は100日までです。100日以上の日付範囲を指定すると、

#HTTPBadRequest: Max date range is 100 days

となります。そこで、以下のコードで100日ごとの日付範囲をタプルで作成します。

date_ranges = []
start_range = DATE_s
while start_range < DATE_e:
if start_range+dt.timedelta(days=100) < DATE_e:
date_ranges.append((start_range, start_range+dt.timedelta(days=100)))
start_range = start_range+dt.timedelta(days=101)
else:
date_ranges.append((start_range, DATE_e))
start_range = DATE_e
date_ranges
"""
[(datetime.datetime(2020, 1, 1, 0, 0), datetime.datetime(2020, 4, 10, 0, 0)),
(datetime.datetime(2020, 4, 11, 0, 0), datetime.datetime(2020, 7, 20, 0, 0)),
(datetime.datetime(2020, 7, 21, 0, 0), datetime.datetime(2020, 10, 29, 0, 0)),
(datetime.datetime(2020, 10, 30, 0, 0),
datetime.datetime(2020, 12, 31, 0, 0))]
"""

睡眠データの取得

all_data = []
for date_range in date_ranges:
print(f"Requesting data for {date_range[0].strftime('%Y-%m-%d')} to {date_range[1].strftime('%Y-%m-%d')}.")
range_data = client.time_series("sleep", base_date=date_range[0],end_date=date_range[1])
all_data.append(range_data)
print("Success!!")
"""
Requesting data for 2020-01-01 to 2020-04-10.
Success!!
Requesting data for 2020-04-11 to 2020-07-20.
Success!!
Requesting data for 2020-07-21 to 2020-10-29.
Success!!
Requesting data for 2020-10-30 to 2020-12-31.
Success!!
"""

client.time_series()によって睡眠データを取得します。base_dateとend_dateに先ほど作成したタプルの値が入るようにfor文を回し、結果をリストに入れていきます。

睡眠データから睡眠時間の抽出

sleep_duration = [[all_data[j]["sleep"][i]["duration"] for i in range(len(all_data[j]["sleep"]))] for j in range(len(date_ranges))]
sleep_duration_2020=np.array([])
for i in range(len(date_ranges)):
sleep_duration_2020 = np.append(sleep_duration_2020, sleep_duration[i])

睡眠時間は”duration”の値となります。睡眠データリストの中から、睡眠時間のみを取り出し、睡眠時間リストを作成します。

リストの形状は、365以上のなので、昼寝の分も含まれていると思われます。

sleep_duration_2020.shape
#(397,)

1年間の睡眠時間の要約統計量の表示

睡眠時間を時間(hour)に変換し、pandasのdescribeで要約統計量を表示すると以下のようになります。

sleep_duration_2020_h =sleep_duration_2020/1000/60/60
pd.DataFrame(sleep_duration_2020_h).describe().T
"""
count mean std min 25% 50% 75% max
0 397.0 6.764987 1.850108 1.0 6.316667 6.983333 7.533333 11.7
"""

睡眠時間分布をヒストグラムで表示

睡眠時間データに対して、np.histogramでヒストグラムデータを作成し、matplotlibのbarグラフでヒストグラムを作成しました。

bins = np.linspace(0,12,41)
hist0, bins0 = np.histogram(sleep_duration_2020_h, bins=bins)
bins0=bins0[1:]
width=bins0[1]-bins0[0]
fig,ax=plt.subplots(dpi=120,figsize=(6,4))
ax.bar(bins0,hist0,width=width,alpha=.5,ec="k",label="2020",fc="C0")
ax.legend()
ax.set(xlabel="Sleep time / h",ylabel="Frequency")
plt.tight_layout()
plt.savefig("histogram_sleeptime2020.png",dpi=130)
plt.show()

2019年の睡眠時間ヒストグラム

同様の方法で2019年の睡眠時間ヒストグラムを作成すると以下のようになります。

#2019
DATE_s = "2019-01-01"
DATE_e = "2019-12-31"
DATE_s = dt.datetime.strptime(DATE_s, '%Y-%m-%d')
DATE_e = dt.datetime.strptime(DATE_e, '%Y-%m-%d')
# Create a series of 100-day date-range tuples between start_date and end_date
date_ranges = []
start_range = DATE_s
while start_range < DATE_e:
if start_range+dt.timedelta(days=100) < DATE_e:
date_ranges.append((start_range, start_range+dt.timedelta(days=100)))
start_range = start_range+dt.timedelta(days=101)
else:
date_ranges.append((start_range, DATE_e))
start_range = DATE_e
all_data = []
for date_range in date_ranges:
print(f"Requesting data for {date_range[0].strftime('%Y-%m-%d')} to {date_range[1].strftime('%Y-%m-%d')}.")
range_data = client.time_series("sleep", base_date=date_range[0],end_date=date_range[1])
all_data.append(range_data)
print("Success!!")
sleep_duration = [[all_data[j]["sleep"][i]["duration"] for i in range(len(all_data[j]["sleep"]))] for j in range(len(date_ranges))]
sleep_duration_2019=np.array([])
for i in range(len(date_ranges)):
sleep_duration_2019 = np.append(sleep_duration_2019, sleep_duration[i])
sleep_duration_2019_h =sleep_duration_2019/1000/60/60
pd.DataFrame(sleep_duration_2019_h).describe().T
bins = np.linspace(0,12,41)
hist1, bins1 = np.histogram(sleep_duration_2019_h, bins=bins)
bins1=bins1[1:]
width=bins1[1]-bins1[0]
fig,ax=plt.subplots(dpi=120,figsize=(6,4))
ax.bar(bins1,hist1,width=width,alpha=.5,ec="k",label="2019",fc="C1")
ax.legend()
ax.set(xlabel="Sleep time / h",ylabel="Frequency")
plt.tight_layout()
plt.savefig("histogram_sleeptime2019.png",dpi=130)
plt.show()

2018年の睡眠時間ヒストグラム

2018年の睡眠時間ヒストグラムは以下のようになります。

#2018
DATE_s = "2018-01-01"
DATE_e = "2018-12-31"
DATE_s = dt.datetime.strptime(DATE_s, '%Y-%m-%d')
DATE_e = dt.datetime.strptime(DATE_e, '%Y-%m-%d')
# Create a series of 100-day date-range tuples between start_date and end_date
date_ranges = []
start_range = DATE_s
while start_range < DATE_e:
if start_range+dt.timedelta(days=100) < DATE_e:
date_ranges.append((start_range, start_range+dt.timedelta(days=100)))
start_range = start_range+dt.timedelta(days=101)
else:
date_ranges.append((start_range, DATE_e))
start_range = DATE_e
all_data = []
for date_range in date_ranges:
print(f"Requesting data for {date_range[0].strftime('%Y-%m-%d')} to {date_range[1].strftime('%Y-%m-%d')}.")
range_data = client.time_series("sleep", base_date=date_range[0],end_date=date_range[1])
all_data.append(range_data)
print("Success!!")
sleep_duration = [[all_data[j]["sleep"][i]["duration"] for i in range(len(all_data[j]["sleep"]))] for j in range(len(date_ranges))]
sleep_duration_2018=np.array([])
for i in range(len(date_ranges)):
sleep_duration_2018 = np.append(sleep_duration_2018, sleep_duration[i])
sleep_duration_2018_h =sleep_duration_2018/1000/60/60
#pd.DataFrame(sleep_duration_2018_h).describe().T
bins = np.linspace(0,12,41)
hist2, bins2 = np.histogram(sleep_duration_2018_h, bins=bins)
bins2=bins2[1:]
width=bins2[1]-bins2[0]
fig,ax=plt.subplots(dpi=120,figsize=(6,4))
ax.bar(bins2,hist2,width=width,alpha=1,ec="k",fc="C2",label="2018")
ax.legend()
ax.set(xlabel="Sleep time / h",ylabel="Frequency")
plt.tight_layout()
plt.savefig("histogram_sleeptime2018.png",dpi=130)
plt.show()

睡眠時間ヒストグラムをまとめて表示

2018年から2020年のヒストグラムをまとめて表示すると以下のようになります。

# まとめて表示
fig,ax=plt.subplots(dpi=120,figsize=(6,4))
ax.bar(bins0,hist0,width=width,alpha=.5,ec="k",label="2020")
ax.bar(bins1,hist1,width=width,alpha=.5,ec="k",label="2019")
ax.bar(bins2,hist2,width=width,alpha=.5,ec="k",label="2018")
ax.set(xlabel="Sleep time / h",ylabel="Frequency")
ax.legend()
plt.tight_layout()
plt.savefig("histogram_sleeptime_from2018to2020.png",dpi=130)
plt.show()
コードをダウンロード(.pyファイル)

コードをダウンロード(.ipynbファイル)

参考

Overview — Python-Fitbit 0.3.0 documentation
Fitbit Development: Sleep
You'll fit in here. Using JavaScript, CSS, and SVG, developers now have a fast, easy way to build apps and clock faces f...
Plot your Fitbit data in Python (API v1.2) | Shane Lynn
Use the Python Fitbit library, Matplotlib, and Pandas, to analyse your sleep data. Pull data from Fitbit API into a Pand...

コメント