OBDから取得した車両データをDashとPlotly Expressで可視化する その2

前回からの続きで、車両データを地図上にプロットする方法を記載します。

＊前回記事
[OBDから取得した車両データをDashとPlotly Expressで可視化する その1](https://qiita.com/banquetkuma/items/37ef3f543735560d2b1b)

#この記事の内容
・走行中のGPSデータの取得方法
・Mapboxを使った地図上への車両データのプロット方法

#実行環境
macOS Mojave version10.14.5
Python 3.7.2
dash 1.0.0
dash-core-components 1.0.0
dash-html-components 1.0.0
plotly-express 0.3.1
pandas 0.24.2

#Mapboxとは
簡単な操作で独自の地図を作成できるアプリ開発者向けのプラットフォームです。
元となる地図は、[OpenStreetMap](https://www.openstreetmap.org/#map=5/35.588/134.380)なので、著作権フリーで利用することができます。また、月50,000ロードまで無料で使えます。

＊Mapbox
https://www.mapbox.com/
＊Mapbox pricing
https://www.mapbox.com/pricing/#maploads

#可視化前に必要なこと（access tokenの取得）
Mapboxを使って地図上にデータをプロットするには、
作成した地図のaccess tokenを取得する必要が有ります。
access tokenをDash、Plotly Express内で参照し、読み込んだ地図の上にプロットする仕組みです。
ここでは、地図の作成方法とaccess tokenの取得方法は割愛しますが、以下の記事が非常に参考になりました。
[Mapboxを使って地図表示をしてみよう！]
(https://developer.cybozu.io/hc/ja/articles/360000072923-Mapbox%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E5%9C%B0%E5%9B%B3%E8%A1%A8%E7%A4%BA%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%88%E3%81%86-)

#GPSデータの取得方法
OBDから取得したデータには位置情報が含まれないため、別の方法で取得する必要が有りました。
まず思いつくのはカーナビですが、アクセス方法をメーカーに問い合わせるのが面倒だったので簡単なアプリを使うことにしました。
使ったアプリは[GPSログからCSV作成 ](https://apps.apple.com/jp/app/gps%E3%83%AD%E3%82%B0%E3%81%8B%E3%82%89csv%E4%BD%9C%E6%88%90/id738258568)というものです、これはアプリを起動中のiPhoneの位置情報をCSVではき出してくれるという代物です。これを発進時にON、停車時にOFFして走行中の位置情報を取得しました。![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318960/0bdf1a7d-4b65-7080-5452-4295dc1caf09.png)

CSVファイルの中は以下のようになっています。ありがたいことに既に整然データになっていました。
この中で使う列は「lat（緯度）」、「lng（経度）」、「date（日時）」の3つです。
これらを車両データのDataFrameに加えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318960/9e563e92-1413-809c-3663-67cb1ca500d1.png)

#データの整形
ここでは、
「GPSログからCSV作成」と「Stanislav Svistunov Car Scanner ELM OBD2」（＊[その1](https://qiita.com/banquetkuma/items/37ef3f543735560d2b1b)参照）でデータを記録し始めた時刻を同じと仮定します。つまり、いずれも2019-05-04 13:00:00から記録開始されたとしました。データ取得のタイミングがそれぞれのアプリで同期していないので両者を完全に紐付けられませんが、その時刻にその"付近"に車があったことは間違いないので、この方法で進めました。

以下の車両データのDataFrameに
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318960/d090c14c-836c-98fe-e99e-d880c5ca07a6.png)


「GPSログからCSV作成」で作ったCSVをDataFrameに変換した後、
「lat（緯度）」、「lng（経度）」列を加え、「日時（date)」が共通する行だけ取り出します。
すると以下のようなDataFrameが作れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318960/96e9c4b7-45d7-773e-351e-4402629ba6a8.png)
一旦CSVに保存しておき、後でDashの中で読み込みます。
ここまでくれば、後はDashとplotly-expressで可視化するだけです。

#DashとPlotly Expressを使った可視化

[その1](https://qiita.com/banquetkuma/items/37ef3f543735560d2b1b)と同様に、Dashの中でPlotly Expressを動かします。
callbackの下に書いたmake_figure関数に、value、colorに取る物理量（DataFrameの列に相当）を渡します。そして、`return px.scatter_mapbox（...)`でPlotly Expressで作図した散布図を返すようにしました。

単純な散布図と違うのは、Mapboxで作成した地図上にプロットしたことです。
これは、
`px.set_mapbox_access_token`の後にMapboxのaccess tokenを書き、
`px.scatter_mapbox`の中で`lat`にDateFrameの「緯度」列、`lon`に「経度」列を代入することで可能になります。




```python

import plotly_express as px
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import pandas as pd

GPS = pd.read_csv("上で整形したCSVのパスを書きます")

col_options = [dict(label=x, value=x) for x in GPS.columns]
dimensions = ["value","color"]

app = dash.Dash(
    __name__, external_stylesheets=["https://codepen.io/chriddyp/pen/bWLwgP.css"]
)

app.config['suppress_callback_exceptions']=True

app.layout = html.Div(
    [
        html.H1("Visualization of both OBD and GPS by Dash"),
        html.Div(
            [
                html.P([d + ":", dcc.Dropdown(id=d, options=col_options)])
                for d in dimensions
            ],
            style={"width": "25%", "float": "left"}
        ),
        dcc.Graph(id="graph", style={"width": "75%", "display": "inline-block"}),
    ]
)

@app.callback(Output("graph", "figure"), [Input(d, "value") for d in dimensions])
def make_figure(value,color):
    px.set_mapbox_access_token("ここにMapboxのaccess tokenを書きます")

    return  px.scatter_mapbox(GPS,
                        lat="緯度　(°)",
                        lon="経度　(°)",
                        color=color,
                        size=value,
                        size_max=10,
                        zoom=10,
                        color_continuous_scale=px.colors.cyclical.IceFire,
                        hover_name=value)
　　#px.scatter_mapbox(...)はplotly_expressの描画部分

if __name__ == '__main__':
    app.run_server(debug=True)
```

上のコードを実行すると、ブラウザ上で以下のアプリケーションが立ち上がります。
まず、valueに「速度(km/h)」、colorに「燃費(km/l)」を選んでみます。
すると以下のようなグラフが書けます。点のサイズは「速度(km/h)」、色は「燃費(km/l)」を
表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318960/5fb5f972-c6af-4c09-8032-b3d8256b1ca9.png)

これは、来来亭 桂川店　→（京都縦貫道）→　湯の花温泉　の走行データですが、
市街地よりも高速道路で燃費が高い傾向にあることが分かりました。
ただし、高速入口の合流は、吹かすせいか市街地より低めです。

以下にアプリケーションを上げていますので、触っていただいて何か発見があれば連絡いただければ幸いです。
[Visualization of both OBD and GPS by Dash]
(https://obdmapbox.herokuapp.com/)

#その2終了
その2では、OBDから取得した車両データをMapboxを使って地図上にプロットしました。


次回はいつになるか分かりませんが、
Raspberry Piを使って
データ取得 → 整形 → 可視化を走行中にon-siteで行う話を書きたいと思います。