AmbientのデーターをPythonで読み込み、pandasのDataFrameに変換してグラフ化などをおこなう事例を紹介します。事例として扱うデーターはESP8266 Arduinoで測定した気温、湿度、気圧などのデーターで、「ベランダ環境モニター@世田谷桜丘」として公開しているものです。

Pythonを実行した環境は

  • Mac OS X 10.11.6
  • Python 3.5.2 :: Anaconda 4.2.0
  • jupyter 4.2.0

です。

AmbientのPythonライブラリーのインストール

AmbientのPythonライブラリーにはAmbientにデーターを送信する機能と、Ambientに蓄積されたデーターを読み込む機能があります。

ライブラリーはGithubから次のようにライブラリーをインストールできます。

$ pip install git+https://github.com/TakehikoShimojima/ambient-python-lib.git

ライブラリーの詳細は「Pythonライブラリー」をご覧ください。

Ambientライブラリーを読み込む

In [1]:
import ambient

Ambientからデーターを読み込む

データーを読み込むためには、まずチャネル、ライトキー、リードキーを指定してインスタンスを作ります。
読み込むだけならライトキーは何でもよく、’’でもよいです。公開チャネルならリードキーは省略可能です。
今回事例として扱うデーターは「ベランダ環境モニター@世田谷桜丘」として公開しているもので、チャネルIdは102ですので、下記のようにインスタンスを作ることができます。

In [2]:
am = ambient.Ambient(102, '')

データーの読み込みにはデーター件数を指定する方法、日付を指定する方法、期間を指定する方法があります。
日付を指定して読み込んでみます。

In [3]:
d = am.read(date='2017-03-03')

読み込んだデーターは辞書形式の配列になります。データーの生成時刻(‘created’)は協定世界時(UTC)の文字列です。データーは昇順(古いものから新しいものへ)に並びます。

In [4]:
d[:3]
Out[4]:
[{'created': '2017-03-02T15:03:56.000Z',
  'd1': 7.5,
  'd2': 82.7,
  'd3': 997.4,
  'd5': 0},
 {'created': '2017-03-02T15:08:55.000Z',
  'd1': 7.4,
  'd2': 82.6,
  'd3': 997.4,
  'd5': 0},
 {'created': '2017-03-02T15:13:54.000Z',
  'd1': 7.4,
  'd2': 82.4,
  'd3': 997.3,
  'd5': 0}]

pandas DataFrameに変換する

まずこの先で必要になるモジュールを読み込みます。

In [5]:
import pandas as pd
import numpy as np
from datetime import datetime as dt
import pytz

次にデーターをpandasのDataFrameに変換します。

In [6]:
df = pd.DataFrame(d)
df.head(3)
Out[6]:
created d1 d2 d3 d4 d5
0 2017-03-02T15:03:56.000Z 7.5 82.7 997.4 NaN 0.0
1 2017-03-02T15:08:55.000Z 7.4 82.6 997.4 NaN 0.0
2 2017-03-02T15:13:54.000Z 7.4 82.4 997.3 NaN 0.0
In [7]:
type(df['created'][0])
Out[7]:
str

データーの生成時刻df[‘created’]が文字列で、後の処理が不便なので、これをpandasのTimestampに変換しておきます。

In [8]:
df['created'] = pd.to_datetime(list(df['created'])).tz_localize('GMT').tz_convert('Asia/Tokyo').tz_localize(None)
type(df['created'][0])
Out[8]:
pandas.tslib.Timestamp

pd.to_datetime()に時刻データーのリストを渡すとTimestampにしてくれます。そのままだと協定世界時(UTC)で表示されてタイムゾーンは持っていないので、タイムゾーンをGMTに設定してから、Asia/Tokyoにしています。その上で.tz_localize(None)でタイムゾーンを外し、ローカルタイム表示にしておきます。

最初は次のようにしていました。

def parse_date(x):
    t = dt.strptime(x, '%Y-%m-%dT%H:%M:%S.%fZ')
    return pytz.utc.localize(t).astimezone(pytz.timezone('Asia/Tokyo'))
df['created'] = df['created'].apply(parse_date)

type(df['created'][0])

strptime()で文字列をDatetimeに変換し、タイムゾーンとして日本(‘Asia/Tokyo’)を設定しています。

pandasのread_csvだと文字列形式の時刻をパースしてTimestampに変換する機能があります。辞書形式の配列からDataFrameを作る時も同じような機能があるように思いますが、見つけられなかったため、上記のように自力で変換しました。

df['created'] = df['created'].apply(lambda x: pytz.utc.localize(dt.strptime(x, '%Y-%m-%dT%H:%M:%S.%fZ')).astimezone(pytz.timezone('Asia/Tokyo')))

というlambdaを使った方法もありますが、かえって分かりにくいと思います。

In [9]:
df = df.set_index('created')

‘created’をindexとして設定しておきます。

データーをmatplotlibでグラフ化する

In [10]:
%matplotlib inline
import matplotlib.pyplot as plt

読み込んだ3月3日の温度を折れ線グラフにしてみます。

In [11]:
df.plot(y='d1')
Out[11]:
<matplotlib.axes._subplots.AxesSubplot at 0x1158e7da0>

温度と湿度の相関をグラフ化してみます。

In [12]:
df.plot.scatter(x='d1', y='d2')
Out[12]:
<matplotlib.axes._subplots.AxesSubplot at 0x117f12f98>

一日の温度と湿度の変化を温度を左軸、湿度を右軸にしてグラフにしてみます。

In [13]:
fig, ax1 = plt.subplots()
ax1.plot(df['d1'])
ax2 = ax1.twinx()
ax2.plot(df['d2'], 'r')
plt.show()

上記と同じ温度と湿度の移動平均を計算してグラフ化してみます。データーとしてdf[‘d1’]の代わりにdf[‘d1’].rolling(window=7, min_period=1).mean()とすることで幅7の移動平均を計算できます。

In [14]:
fig, ax1 = plt.subplots()
ax1.plot(df['d1'].rolling(window=7, min_periods=1).mean())
ax2 = ax1.twinx()
ax2.plot(df['d2'].rolling(window=7, min_periods=1).mean(), 'r')
plt.show()

気温、湿度、気圧、電源電圧、照度の散布図行列を作ってみます。

In [15]:
plt.figure()
from pandas.tools.plotting import scatter_matrix
scatter_matrix(df)
plt.show()
<matplotlib.figure.Figure at 0x1186052e8>

Ambientのチャネル情報を取得し、グラフの凡例や軸名に使う

getprop()でチャネル情報を取得します。’d1’に設定したデーター名はprop[‘d1’][‘name’]で参照できます。

In [16]:
prop = am.getprop()
prop['d1']['name']
Out[16]:
'温度(℃)'

matplotlibのグラフの凡例、グラフ軸名に反映させます。まず、日本語が使えるようにします。

In [17]:
from matplotlib import font_manager
fontprop = font_manager.FontProperties(fname="/Library/Fonts/Osaka.ttf")

d1が温度ですが、これをグラフの凡例とy軸名として表示します。

In [18]:
plt.figure()
df.plot(y='d1')
plt.legend([prop['d1']['name']], prop = fontprop)
plt.ylabel(prop['d1']['name'], fontproperties=fontprop)
Out[18]:
<matplotlib.text.Text at 0x11990d278>
<matplotlib.figure.Figure at 0x119684e80>

d1(温度)とd2(湿度)を左右のy軸でグラフ化し、凡例とy軸名を表示します。

In [19]:
fig, ax1 = plt.subplots()
ax1.plot(df['d1'])
ax1.set_ylabel(prop['d1']['name'], fontproperties=fontprop)
ax2 = ax1.twinx()
ax2.plot(df['d2'], 'r')
ax2.set_ylabel(prop['d2']['name'], fontproperties=fontprop)
lines, labels = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
l = list(map((lambda x: prop[x]['name']), labels))
l2 = list(map((lambda x: prop[x]['name']), labels2))
ax2.legend(lines + lines2, l + l2, prop=fontprop)
plt.show()

まとめ

AmbientとPython、pandas、matplotlibを組み合わせることで、マイコンで制御したセンサーデーターを蓄積し、簡単な可視化(グラフ化)はAmbientでおこない、さらに柔軟な分析、可視化をPythonでおこなえるようになります。実際のセンサーデーターをPythonで分析する場合の参考になればうれしいです。