やっぱり、計測する度にどの程度目標達成したかを視覚的に掴みたいところ。というわけで、
Google Chart Tools / Image Charts (aka Chart API)を使って適当な折れ線グラフを出力してみる。基本的にカンマ区切りでデータを渡してやればあとは適当にやってくれるのでとても楽。Chart Wizardでインタラクティブに項目の調整なども出来るし。
ということでこんな感じのグラフがさっくり作れた。けど、このまま使うと「データがある分だけ等間隔に表示」ということになり、時間軸を正しく反映はしない。とはいえ今回のサービスって「毎日あるタイミングで体重を測定する」ってのを想定してるので、実用上そんなに問題は無いはず。と思ってたところ突っ込みを食らったので少々真面目に考えることに。
やること
・指定した時間レンジ内での変化を平滑化する
・指定した時間レンジよりもデータ量が少なければ空データを補完する
ここで、「過去1週間分を表示するけど未参加時期の分は表示しない」という仕様にする場合は一旦出力用のリストの各要素を'0'で初期化しておけば後が楽そう。
時間レンジの切り方には色々あると思うけれど今回は「最新の計測日時から24時間ずつ逆にたどっていき、その中で得られたデータについては平均値を取る」ということにした。極端に平滑化されたグラフが欲しいわけじゃないので移動平均とかは取らない。
Pythonのコードだとこんな感じ。
def getDailyHistoricalData(self, periodsToBack): info = self._fetchWeightLog() normalizeFor = 86400 info.sort(key=lambda x:x['ts'], reverse=True) lastBoundary = info[0]['ts'] - normalizeFor avgList = list() cnt = 0 sum = 0 for v in info: if lastBoundary < float(v['ts']): sum += float(v['wt']) cnt += 1 else: avgList.append(('%.2f' % (sum / cnt)) if cnt != 0 else '0') lastBoundary -= normalizeFor cnt = 0 sum = 0 if pos == periodsToBack: break # catch last one if cnt != 0: avgList.append(('%.2f' % (sum / cnt)) if cnt != 0 else '0') if len(avgList) < periodsToBack: avgList.extend(['0' for i in range(periodsToBack - len(avgList))]) avgList.reverse() return avgList最新データから逆に古いデータへ辿っていく形で、データが足りなければ最後のほうで追加してる。リスト長が固定なのでインデックス指定でいじってもいいのだけど、appendでペチペチやっていくのが楽だったので最後にreverseかけてる。 これで無事一日でデータ投入しまくっても平均値のみ1日1回分反映されるようになった。けれど多分これは不具合ある。1日・2日と計測をサボった際、この実装だとその区間データは0になるはずなんだけど、どっちかというと補完処理してほしいだろうなぁ。
で、Google Image Chartsは http://chart.apis.google.com/chart?chs=220x110&cht=lc&chco=3072F3&chm=B,DDDDFF,0,0,0&chd=t:1,2,3,4 というようなURLでimgタグを貼るとグラフ描画してくれるよという程度。あとはChart Wizardのギャラリーとか見ながら頑張るのがいい。使える記法のリファレンスは結構長い。
0 件のコメント:
コメントを投稿