こんにちは。
現役エンジニアの”はやぶさ”@Cpp_Learningです。最近ダイエットしてます。
ダイエット期間中の体重データを可視化することでモチベーションをキープしてます💪
Pythonプログラミングで体重データを可視化することで、ダイエットのモチベーションが向上しました💪 pic.twitter.com/kXIt60wUph
— はやぶさ@技術ノート (@Cpp_Learning) January 16, 2021
本記事ではPythonプログラミングによるグラフのGifアニメーション作成について紹介します。
データ分析のための可視化デザインについても簡単に紹介します
Contents
リングフィットアドベンチャーでダイエット
冒頭に書いた通り、最近ダイエットしてます。色々なことにトライしましたが、最も効果的だと感じたのが、リングフィットアドベンチャーで楽しく運動することです。
正直ゲームだと思って甘くみてました。ゲーム開始から20分で大量の汗が!運動不足もあってか最初の三日間は全身筋肉痛でした(笑)
ボス戦でもうダメだ―ってときには、相棒からの「まだやれる!」の声援のおかげで、最後まで筋トレをやりきれました!
『キツイ⇒「まだやれる!」⇒頑張る』のスパイラル~
ダイエットに関する前知識も教えてくれるし、「スクワット200回達成です♪」など、事あるごとに褒めてくれるのが嬉しくて、ついつい頑張ってしまいます。
実践!Pythonプログラミングで体重データの可視化
リングフィットアドベンチャーが、その日の運動時間や消費カロリーを教えてくれますが、さすがに体重管理まではしてくれないので、自分で計測して記録しています。
その記録を可視化することで「ダイエットをはじめて何日後に痩せたか?」などを把握しながら、ダイエットを楽しんでいます。
以降からPythonプログラミングによるデータの可視化についてソースコードを付きで紹介します。
インストール
PythonでグラフのGifアニメーションをつくる方法はいくつか存在しますが、gif|GitHubを活用するのがオススメです。
以下のコマンドでインストールできます。
pip install gif
以降からコード書いていきます。
Google Colabで動作確認しました。
Import
まずはimportから
1 2 3 4 |
import pandas as pd from matplotlib import pyplot as plt import datetime import gif |
データフレーム
今回は各データを手打ちします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# ダイエット期間 START = pd.Timestamp("2020-01-05") END = pd.Timestamp("2020-01-16") # データ weights = [66.7, 66.7, 65.8, 65.6, 67.0, 66.5, 65.9, 65.1, 64.7, 64.5, 64.8, 66.1] ringfit = [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1] # リングフィットした:1, してない:0 # データフレーム化 df = pd.DataFrame( { "date": pd.date_range(start=START, end=END), "weight": [wi for wi in weights], "ringfit": [fi for fi in ringfit], } ) # 表を出力 df |
上のデータが今回の可視化対象です。
簡単なデータ可視化
簡単な可視化ならコード1行で実現できます。
1 2 3 |
plt.plot(df["date"], df["weight"]); |
ただ上図だと大事なことが伝わらないので、工夫していきます。
丁寧なデータ可視化
各種設定して、一目で分かるデータ可視化を目指します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# 図のサイズ設定 fig = plt.figure(figsize=(12,6), dpi=100) ax = fig.add_subplot(1,1,1) # プロット設定 ax.plot(df["date"], df["weight"], color='green', marker='o', markersize=8, linestyle='dashed', linewidth=2) # 軸の範囲 ax.set_xlim([START, END]) ax.set_ylim([60, 70]) # 軸の目盛設定 ax.set_xticks([i for i in df["date"]]) ax.set_xticklabels(['1days', '2days', '3days', '4days', '5days', '6days', '7days', '8days', '9days', '10days', '11days', '12days']) ax.set_yticks([60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70]) # 目盛りの文字サイズ設定 ax.xaxis.set_tick_params(direction="out", labelsize=16, width=3, pad=10) ax.yaxis.set_tick_params(direction="out", labelsize=16, width=3, pad=10) # 軸のラベル設定 ax.set_xlabel("Date", fontsize=16, labelpad=20, weight='bold') ax.set_ylabel("Body weight [kg]", color='tab:green', fontsize=16, labelpad=20, weight='bold') # グラフのタイトル ax.set_title("Log body weight in 2021", fontsize=16, fontweight=16) # グリッド設定 ax.grid(True); |
各軸の説明やタイトルをつけることで、何のデータなのか明確になりました。ここから、もう少し工夫します。
目的・目標が分かるデータ可視化
今回はダイエット期間中のデータなので、目標の体重値を追加してあげます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# 図のサイズ設定 fig = plt.figure(figsize=(12,6), dpi=100) ax = fig.add_subplot(1,1,1) # 目標値 th = 63.0 ax.hlines(y=th, xmin=START, xmax=END, colors="red", linestyle="--", lw=3) ax.text(x=df["date"].mean(), y=th+0.5, s="Target Level", color="red", ha='center', va='center', fontsize=16) # プロット設定 ax.plot(df["date"], df["weight"], color='green', marker='o', markersize=8, linestyle='dashed', linewidth=2) # 軸の範囲 ax.set_xlim([START, END]) ax.set_ylim([60, 70]) # 軸の目盛設定 ax.set_xticks([i for i in df["date"]]) ax.set_xticklabels(['1days', '2days', '3days', '4days', '5days', '6days', '7days', '8days', '9days', '10days', '11days', '12days']) ax.set_yticks([60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70]) # 目盛りの文字サイズ設定 ax.xaxis.set_tick_params(direction="out", labelsize=16, width=3, pad=10) ax.yaxis.set_tick_params(direction="out", labelsize=16, width=3, pad=10) # 軸のラベル設定 ax.set_xlabel("Date", fontsize=16, labelpad=20, weight='bold') ax.set_ylabel("Body weight [kg]", color='tab:green', fontsize=16, labelpad=20, weight='bold') # グラフのタイトル ax.set_title("Log body weight in 2021", fontsize=16, fontweight=16) # グリッド設定 ax.grid(True); |
この一工夫で「あと何キロ痩せれば良いか」が明示できます。
このグラフを俯瞰してみると、ダイエット4日目と10日目に谷が二つあることが分かります。つまりリバウンドしてますね…
リバウンドの原因については、グラフのGifアニメーションを作りながら説明します。
実践!Pythonプログラミングでグラフのアニメーションをつくる
gif|GitHubによるGifアニメーション作成は、以下の3ステップで実現できます。
- Gifアニメーション用のPlot関数を作成
- for文で1フレームつずつ描画
- 全フレームをGifで保存
順番にコード書いていきます。
グラフのGifアニメーション作成用の関数
最初に今まで書いたデータ可視化のコードを少し改良して、関数化します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
@gif.frame def my_plot(df, date, x_min, x_max, y_min, y_max): # 可視化するデータ d = df[df["date"] <= date] # 図のサイズ設定 fig = plt.figure(figsize=(12,6), dpi=100) ax = fig.add_subplot(1,1,1) # 目標値 th = 63.0 ax.hlines(y=th, xmin=x_min, xmax=x_max, colors="red", linestyle="--", lw=3) ax.text(x=df["date"].mean(), y=th+0.5, s="Target Level", color="red", ha='center', va='center', fontsize=16) # ダイエットしなかった日のdf bad_df = d[d["ringfit"]==0] # ダイエットできなかった期間 for bad_day in bad_df["date"]: start = bad_day - datetime.timedelta(hours=12) end = bad_day + datetime.timedelta(hours=12) ax.axvspan(xmin=start, xmax=end, alpha=0.3, color='#F933FF') ax.text(x=bad_day, y=d["weight"].max()+0.5, s='I did not play "Ring Fit"', color="red", ha='center', va='center', fontsize=16) # プロット設定 ax.plot(d["date"], d["weight"], color='green', marker='o', markersize=8, linestyle='dashed', linewidth=2) # 軸の範囲 ax.set_xlim([x_min, x_max]) ax.set_ylim([y_min, y_max]) # 軸の目盛設定 # ax.set_xticklabels(['1days', '2days', '3days', # '4days', '5days', '6days', # '7days', '8days', '9days', # '10days', '11days', '12days']) ax.set_yticks([60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70]) # 目盛りの文字サイズ設定 ax.xaxis.set_tick_params(direction="out", labelsize=16, width=3, pad=10) ax.yaxis.set_tick_params(direction="out", labelsize=16, width=3, pad=10) # 軸のラベル設定 ax.set_xlabel("Date", fontsize=16, labelpad=20, weight='bold') ax.set_ylabel("Body weight [kg]", color='tab:green', fontsize=16, labelpad=20, weight='bold') # グラフのタイトル plt.title("Log body weight in 2021", fontsize=16, fontweight=16) # グリッド設定 ax.grid(True); |
※今まで書いたコードと、どこが違うか見比べてみて下さい
アニメーション作成とGifで保存
以下のコードでグラフのアニメーションを作成して、Gifで保存できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 各軸の最小値と最大値 x_min = df["date"][0] x_max = df["date"][len(df)-1] y_min = 60 y_max = 70 # グラフのアニメーション作成 frames = [] for date in df["date"]: frame = my_plot(df, date, x_min, x_max, y_min, y_max) frames.append(frame) # gifを保存 gif.save(frames, path='./weight-log.gif', duration=3.5, unit="s", between="startend") |
※保存先のpathは適当に変更してください。
Pythonプログラミングで体重データを可視化することで、ダイエットのモチベーションが向上しました💪 pic.twitter.com/kXIt60wUph
— はやぶさ@技術ノート (@Cpp_Learning) January 16, 2021
保存した“weight-log.gif”を再生したものが上図です(冒頭で見せたものと同じです)
アニメーションにすることで「何日目までは順調に体重が落ちてる」・「この日を境にリバウンドしてる」などの時系列をより意識できますね。
なぜリバウンドしたのかの原因もアニメーション見れば分かりますね。少し怠けると直ぐに体重に変化がでますね…継続は力なり💪
おわりに
データ可視化により、様々な情報を整理することができました。
丁寧なデータ可視化は自分だけでなく相手にデータを知ってもらうときの有効な手段になります。
少し大変かもしれませんが、「何が重要か?」・「どこをアピールしたいか?」などを意識してデータを可視化できると良いと思います。
【おまけ】ダイエットとプログラミング
フクロウの”くるるちゃん”と一緒に日々ダイエットに励んでいます💪
サゲテプッシュ
大胸筋が鍛えられますᕦ(ò_óˇ)ᕤ
リングフィットアドベンチャーは「運動不足を解消するための運動をする体力がない」っていうどうしようもない方におすすめです◎#リングフィット pic.twitter.com/cWYvJ4oINO
— くるる@フクロウ界のアイドル (@kururu_owl) December 28, 2020
ダイエットについてですが、リングフィットアドベンチャー以外にも、いくつかトライしていることがあるので簡単に紹介します。
21時までに夕食を済ませ、メインの飲み物をプーアル茶にしました。
あとダイエットという身近な題材にプログラミンが活用できることを紹介しました。
と感じている人たちのプログラミングに対するハードルを少しでも下げれたら嬉しく思います。
プログラミング言語いくつかありますが、Pythonプログラミングに挑戦したい人は「ゼロから学ぶPythonプログラミング」という本がオススメです。
感想文の記事も書いてるので、ご参考までに。