csvを扱うモジュールをインポートし、その中にあるreaderというメソッドを使う。返値は読み込んだデータ全体をオブジェクトとして持っているので一行ずつ取り出すには次のようにfor文を書く。
これを実行し、x_data, y_dataに何が入っているかを確かめること。
下の例では、
1,B0-FC-46-01-14-A6-43-A1-AB-CD-CB-9C-FD-DB-40-13,-63,-63,1.01076,far,2016/07/07 09:41:45.782 1,B0-FC-46-01-14-A6-43-A1-AB-CD-CB-9C-FD-DB-40-13,-60,-63,0.613913253540759,far, 2016/07/07 09:41:46.597 1,B0-FC-46-01-14-A6-43-A1-AB-CD-CB-9C-FD-DB-40-13,-62,-63,0.852140880208678,far, 2016/07/07 09:41:47.561
のように3列目にシグナル強度(rssi)、7列目に年月日が入っている場合を扱っている。
# coding:utf-8
'''
BLEデータの読み込み、プロット
モジュールcsvをつかってみる
'''
import csv
datafile = open('testData.txt', 'r') # ファイル名は適当に変更
csvObject = csv.reader(datafile)
x_data = []
y_data = []
for row in csvObject:
x_data.append(row[6])
y_data.append(row[2])
x_data
y_data
x_dataは文字列なのでこのままでは描画できない。日時データであることを認識させなければならない。そのためにはdatetimeモジュールにある文字列型⇒datetime型の変換メソッドを用いる。 strptimeの第1引数は文字列、第2引数は文字列の形式
from datetime import datetime
datetime.strptime(x_data[1],'%Y/%m/%d %H:%M:%S.%f')
横軸のラベルはmatplotlib.datesモジュールを使う必要があることが面倒ではある (下のpandasを使った描画に日付目盛の詳細な設定例があるので参照してほしい。)
図をnotebook内に書き込むには、スクリプトの先頭に %matplotlib inline を書く。
# coding:utf-8
'''
BLEデータの読み込み、プロット
モジュールcsvをつかってみる
'''
import csv
from datetime import datetime
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
datafile = open('ble20170120_1427.csv', 'r')
csvObject = csv.reader(datafile)
x_data = []
y_data = []
for row in csvObject:
x_data.append(datetime.strptime(row[0],'%Y-%m-%d %H:%M:%S.%f')) # 文字列をdatetimeオブジェクトに変換
y_data.append(row[2])
plt.plot_date(x_data, y_data, "r-")
# x軸をdatetime用の表示にする
# gcaは get current axesの意味
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
plt.gca().xaxis.set_major_locator(mdates.DayLocator())
plt.show()
いくつものグラフを並べて書くときには、subplot関数を利用するのが便利である。
軸を操作するときなど、それぞれのsubplotの返値をオブジェクト変数に記憶しておいて、そのオブジェクトのメソッドをつかうところに注意
# coding:utf-8
'''
BLEデータの読み込み、プロット
モジュールcsvをつかってみる
'''
import csv
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
datafile = open('ble20170120_1427.csv', 'r')
csvObject = csv.reader(datafile)
x_data_raw = []
x_data = []
y_data = []
for row in csvObject:
x_data.append(datetime.strptime(row[0],'%Y-%m-%d %H:%M:%S.%f'))
y_data.append(row[2])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x_data, y_data)
# x軸の時刻表示
minutes = mdates.MinuteLocator()
daysFmt = mdates.DateFormatter('%H:%M:%S')
ax.xaxis.set_major_locator(minutes)
ax.xaxis.set_major_formatter(daysFmt)
fig.autofmt_xdate()
plt.show()
表形式のデータを扱うにはpandasモジュールが便利である。 特に、そのあと統計処理を行う場合には特によく用いられる。
pandaのメソッドplot関数を用いると時系列データを自動認識してくれ、簡単に描ける。もちろん、データをdatetime型に変換しておかなければならない。 pandasのプロット関数の引数はいろいろな形式がある。下の例は、dataFrameの列を整数で指定したもの。
このように、簡単に書けるが、dataFrameの構造は慣れるのに時間がかかる。英語のマニュアルを嫌がらずに読む必要がある。
# coding:utf-8
'''
BLEデータの読み込み、プロット
header行は無し
1列目が日時、3列目がrssi
'''
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
df = pd.read_csv('ble20170120_1427.csv', header=None, encoding='utf-8') # 読み込み
df[0] = pd.to_datetime(df[0]) # 1列目を文字列から日時オブジェクトに変換
ax = plt.figure(figsize=(7,4), dpi=100).add_subplot(111) # 描画ウィンドウの確保
df.plot(x=0, y=2, ax=ax, label="rssi") # 描画ウィンドウに描画
seconds = mdates.SecondLocator(interval=1) # 副目盛の定義
ax.xaxis.set_minor_locator(seconds) # 副目盛をセット
#ax.xaxis.set_minor_formatter(mdates.DateFormatter('%S')) # 副目盛に文字を入れる
ax.xaxis.set_major_formatter(mdates.DateFormatter('%M:%S')) # 主目盛のセット
ax.set_xlabel("time")
ax.set_ylabel("rssi")
plt.show()
次のようにプロットする部分を関数にしておけば、ファイル名を関数の引数にして実行するだけで図示できる。ノートに図を次々書いてメモと一緒に保存しておける。
# coding:utf-8
'''
BLEデータの読み込み、プロット
header行は無し
1列目が日時、3列目がrssi
'''
import pandas as pd
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
def plotBLEdata(filename):
df = pd.read_csv(filename, header=None, encoding='utf-8') # 読み込み
df[0] = pd.to_datetime(df[0]) # 1列目を文字列から日時オブジェクトに変換
ax = plt.figure(figsize=(7,4), dpi=100).add_subplot(111) # 描画ウィンドウの確保
df.plot(x=0, y=2, ax=ax, label="rssi") # 描画ウィンドウに描画
seconds = mdates.SecondLocator(interval=1) # 副目盛の定義
ax.xaxis.set_minor_locator(seconds) # 副目盛をセット
#ax.xaxis.set_minor_formatter(mdates.DateFormatter('%S')) # 副目盛に文字を入れる
ax.xaxis.set_major_formatter(mdates.DateFormatter('%M:%S')) # 主目盛のセット
ax.set_xlabel("time (min:sec)")
ax.set_ylabel("rssi")
plt.show()
%matplotlib inline
plotBLEdata('ble20170120_1427.csv')
%matplotlib auto
# inlineで描画したいときは auto のかわりに inlineを指定
# coding:utf-8
'''
BLEデータの読み込み、プロット
モジュールcsvをつかってみる
'''
import csv
from datetime import datetime
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
datafile = open('./20170202/raspi3_ble20170202.csv', 'r') # 読み込むファイル名
csvObject = csv.reader(datafile)
data = {}
# BLE addressごとのリストにする
for row in csvObject:
if not row[1] in data:
data[row[1]] = {'x': [], 'y': []}
data[row[1]]['x'].append(datetime.strptime(row[0],'%H:%M:%S')) # 文字列をdatetimeオブジェクトに変換
data[row[1]]['y'].append(row[2])
for addr, values in data.iteritems():
plt.plot_date(values['x'], values['y'], "-", label=addr)
# 凡例表示
plt.gca().legend()
# x軸をdatetime用の表示にする
# gcaは get current axesの意味
seconds = mdates.SecondLocator(interval=1) # 副目盛の定義
plt.gca().xaxis.set_minor_locator(seconds) # 副目盛をセット
#ax.xaxis.set_minor_formatter(mdates.DateFormatter('%S')) # 副目盛に文字を入れる
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%M:%S')) # 主目盛のセット
plt.gca().set_xlabel("time (min:sec)")
plt.gca().set_ylabel("rssi")
plt.show()
パラメータrolling_widthに移動平均する数を指定
pandasのrolling_meanは時代遅れと警告がでるがとりあえずこれを使った。将来、rollingに直す。
# coding:utf-8
'''
BLEデータの読み込み、プロット
'''
import csv
from datetime import datetime, timedelta
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import time
'''
dtypeがdatetimeのnp.arrayを受け取って、移動平均を返す
'''
def rolling_datetime(data, window) :
x = np.array([])
for i in range(data.size) :
x = np.append(x, time.mktime(data[i].timetuple()))
rollingData =pd.rolling_mean(x, window)
x = np.array([])
for i in range(rollingData.size) :
if rollingData[i] == rollingData[i] :
x = np.append(x, datetime.fromtimestamp(rollingData[i]))
else:
x = np.append(x, np.nan)
return x
'''
パラメータ
'''
# 読み込むファイル名
datafile = open('./20170202/raspi2_ble20170202.csv', 'r')
# 移動平均間隔
rolling_width = 4
# 表示するアドレス一覧
dispAddr = ["fe:ee:81:c1:35:9f", "c0:1c:4d:47:ff:61","ec:e0:9c:03:00:5e"]
# c0:1c:4d:47:ff:61, fe:ee:81:c1:35:9f, 4f:74:da:59:11:9b, 75:a3:00:83:89:74, ec:e0:9c:03:00:5e
'''
以下計算
'''
data = {}
#時刻の読み込み
csvObject = csv.reader(datafile)
for row in csvObject:
addr = row[1].strip()
if not addr in data.keys():
data[addr] = {'x': np.array([]), 'y': np.array([])}
# print addr # 1回だけアドレスを出力
data[addr]['x'] = np.append(data[addr]['x'], datetime.strptime("20170202 "+row[0],'%Y%m%d %H:%M:%S')) # 文字列をdatetimeオブジェクトに変換
data[addr]['y'] = np.append(data[addr]['y'],row[2])
# 穴がないようにデータを作成する
plotData = {}
for addr, values in data.iteritems():
if not addr in dispAddr :
continue
plotData[addr] = {'x': np.array([values["x"][0]]), 'y': np.array([values["y"][0]])}
for i in range(1,values["x"].size) :
rec_time =values["x"][i-1] + timedelta(seconds=1)
while values["x"][i] > rec_time :
plotData[addr]['x'] = np.append(plotData[addr]['x'],rec_time)
plotData[addr]['y'] = np.append(plotData[addr]['y'], "-110")
rec_time += timedelta(seconds=1)
plotData[addr]['x'] = np.append(plotData[addr]['x'], values["x"][i])
plotData[addr]['y'] = np.append(plotData[addr]['y'], values["y"][i])
# 描画
ax = plt.figure(figsize=(12,4), dpi=100).add_subplot(111) # 描画ウィンドウの確保
line_style = ["-", "-", "-", "." ,":", "<", ">"] # 線の種類
lineNum =0
for addr, values in plotData.iteritems():
if addr in dispAddr :
#ax.plot_date(values['x'], values['y'], line_style[lineNum], label=addr) # 生データ
# 移動平均 (空白があるとだめ)
y = pd.rolling_mean(values["y"],rolling_width)
x = rolling_datetime(values["x"],rolling_width)
ax.plot_date(x[rolling_width:], y[rolling_width:], line_style[lineNum], label=addr) # 移動平均データ
lineNum+=1
# 凡例表示
ax.legend()
# x軸をdatetime用の表示にする
# gcaは get current axesの意味
seconds = mdates.SecondLocator(interval=1) # 副目盛の定義
ax.xaxis.set_minor_locator(seconds) # 副目盛をセット
#ax.xaxis.set_minor_formatter(mdates.DateFormatter('%S')) # 副目盛に文字を入れる
ax.xaxis.set_major_formatter(mdates.DateFormatter('%M:%S')) # 主目盛のセット
ax.set_xlabel("time (min:sec)")
ax.set_ylabel("rssi")
plt.show()
pandas 0.18.0よりndarrayに対するrolling_mean()ではなく、DataFrameに対するrolling()メソッドを使うように変更された。
# coding:utf-8
'''
BLEデータの読み込み、プロット
pandas 0.18.0 以降なので現在中断中 plotBleMultiAddr2.pyを利用すること
'''
import csv
from datetime import datetime, timedelta
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
'''
パラメータ
'''
# 読み込むファイル名
datafile = open('./20170202/raspi2_ble20170202.csv', 'r')
# 移動平均間隔
rolling_width = 5
# 表示するアドレス一覧
dispAddr = ["fe:ee:81:c1:35:9f","4f:74:da:59:11:9b", "c0:1c:4d:47:ff:61","ec:e0:9c:03:00:5e","75:a3:00:83:89:74"]
# c0:1c:4d:47:ff:61, fe:ee:81:c1:35:9f, 4f:74:da:59:11:9b, 75:a3:00:83:89:74, ec:e0:9c:03:00:5e
'''
以下計算
'''
data = {}
#時刻の読み込み
csvObject = csv.reader(datafile)
for row in csvObject:
addr = row[1].strip()
if not addr in data.keys():
data[addr] = {'x': np.array([]), 'y': np.array([])}
# print addr # 1回だけアドレスを出力
data[addr]['x'] = np.append(data[addr]['x'], datetime.strptime(row[0],'%H:%M:%S')) # 文字列をdatetimeオブジェクトに変換
data[addr]['y'] = np.append(data[addr]['y'],int(row[2]))
# 穴がないようにデータを作成する
df4plot ={}
for addr, values in data.iteritems():
if not addr in dispAddr :
continue
plotData = {'x': np.array([values["x"][0]]), 'y': np.array([values["y"][0]])}
for i in range(1,values["x"].size) :
rec_time =values["x"][i-1] + timedelta(seconds=1)
while values["x"][i] > rec_time :
plotData['x'] = np.append(plotData['x'],rec_time)
plotData['y'] = np.append(plotData['y'], "-110")
rec_time += timedelta(seconds=1)
plotData['x'] = np.append(plotData['x'], values["x"][i])
plotData['y'] = np.append(plotData['y'], values["y"][i])
df4plot[addr] = pd.DataFrame({'rssi': plotData['y']}, index=plotData['x'])
# 描画
ax = plt.figure(figsize=(12,4), dpi=100).add_subplot(111) # 描画ウィンドウの確保
line_style = ["-", "-", "-.", "." ,":", "<", ">"] # 線の種類
lineNum =0
for addr, values in df4plot.iteritems():
if addr in dispAddr :
# 移動平均 (空白があるとだめ)
#ax.plot_date(values['x'], values['y'], line_style[lineNum], label=addr) # 生データ
values.rolling('10s')
#print values
#values.plot(y='rssi', style=[line_style[lineNum]], ax=ax, label=addr) # 移動平均データ
ax.plot(values.rssi, label=addr) # rollingが効かない
lineNum+=1
# 凡例表示
ax.legend()
# x軸をdatetime用の表示にする
# gcaは get current axesの意味
seconds = mdates.SecondLocator(interval=1) # 副目盛の定義
ax.xaxis.set_minor_locator(seconds) # 副目盛をセット
#ax.xaxis.set_minor_formatter(mdates.DateFormatter('%S')) # 副目盛に文字を入れる
ax.xaxis.set_major_formatter(mdates.DateFormatter('%M:%S')) # 主目盛のセット
ax.set_xlabel("time (min:sec)")
ax.set_ylabel("rssi")
plt.show()
とりあえずバージョンである。
rssi強度データと時間(カウント数)幅を与えて、その幅内の最大値の配列を返す関数 maxPrevSequenceを追加し、描画プロットの部分で移動平均の代わりに使うだけでよい。 幅はrolling_widthで設定する。
# coding:utf-8
'''
BLEデータの読み込み、プロット
過去の一定幅(prevWidth)の最高値をプロットする
'''
import csv
from datetime import datetime, timedelta
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import time
'''
dtypeがdatetimeのnp.arrayを受け取って、移動平均を返す
'''
def rolling_datetime(data, window) :
x = np.array([])
for i in range(data.size) :
x = np.append(x, time.mktime(data[i].timetuple()))
rollingData =pd.rolling_mean(x, window)
x = np.array([])
for i in range(rollingData.size) :
if rollingData[i] == rollingData[i] :
x = np.append(x, datetime.fromtimestamp(rollingData[i]))
else:
x = np.append(x, np.nan)
return x
def maxPrevSequence(data, width):
dat = []
for i in range(width-1):
dat = np.append(dat, data[0])
dat = np.append(dat, data)
dat = dat.astype(int)
result = np.zeros(data.size)
for i in range(data.size):
result[i] = np.max(dat[i:i+width-1])
return result
'''
パラメータ
'''
# 読み込むファイル名
datafile = open('./20170202/raspi2_ble20170202p1.csv', 'r')
# 最大値を取る間隔
rolling_width = 4
# 表示するアドレス一覧
dispAddr = ["fe:ee:81:c1:35:9f", "c0:1c:4d:47:ff:61","ec:e0:9c:03:00:5e"]
# c0:1c:4d:47:ff:61, fe:ee:81:c1:35:9f, 4f:74:da:59:11:9b, 75:a3:00:83:89:74, ec:e0:9c:03:00:5e
'''
以下計算
'''
data = {}
#時刻の読み込み
csvObject = csv.reader(datafile)
for row in csvObject:
addr = row[1].strip()
if not addr in data.keys():
data[addr] = {'x': np.array([]), 'y': np.array([])}
# print addr # 1回だけアドレスを出力
data[addr]['x'] = np.append(data[addr]['x'], datetime.strptime("20170202 "+row[0],'%Y%m%d %H:%M:%S')) # 文字列をdatetimeオブジェクトに変換
data[addr]['y'] = np.append(data[addr]['y'],row[2])
# 穴がないようにデータを作成する
plotData = {}
for addr, values in data.iteritems():
if not addr in dispAddr :
continue
plotData[addr] = {'x': np.array([values["x"][0]]), 'y': np.array([values["y"][0]])}
for i in range(1,values["x"].size) :
rec_time =values["x"][i-1] + timedelta(seconds=1)
while values["x"][i] > rec_time :
plotData[addr]['x'] = np.append(plotData[addr]['x'],rec_time)
plotData[addr]['y'] = np.append(plotData[addr]['y'], "-110")
rec_time += timedelta(seconds=1)
plotData[addr]['x'] = np.append(plotData[addr]['x'], values["x"][i])
plotData[addr]['y'] = np.append(plotData[addr]['y'], values["y"][i])
# 描画
ax = plt.figure(figsize=(12,4), dpi=100).add_subplot(111) # 描画ウィンドウの確保
line_style = ["-o", "-s", "-^", "." ,":", "<", ">"] # 線の種類
lineNum =0
for addr, values in plotData.iteritems():
if addr in dispAddr :
#ax.plot_date(values['x'], values['y'], line_style[lineNum], label=addr) # 生データ
# y = pd.rolling_mean(values["y"],rolling_width)
# x = rolling_datetime(values["x"],rolling_width)
x = values["x"]
y = maxPrevSequence(values["y"], rolling_width) # 過去rolloing_width間の最大値をyデータ配列とする
ax.plot_date(x, y, "-", label=addr) # 加工データのプロット
lineNum+=1
# 凡例表示
ax.legend()
# x軸をdatetime用の表示にする
# gcaは get current axesの意味
seconds = mdates.SecondLocator(interval=1) # 副目盛の定義
ax.xaxis.set_minor_locator(seconds) # 副目盛をセット
#ax.xaxis.set_minor_formatter(mdates.DateFormatter('%S')) # 副目盛に文字を入れる
ax.xaxis.set_major_formatter(mdates.DateFormatter('%M:%S')) # 主目盛のセット
ax.set_xlabel("time (min:sec)", fontsize=14)
ax.set_ylabel("rssi",fontsize=14)
plt.show()