移動の軌跡をpythonを用いて地図に表示する&画像化する
移動したときの軌跡を表示
今やGPSがくっついた端末を持ち運ぶことも多いので、 移動の軌跡を表示したい、なんていう要望もあるかと。
そんなことをやってみました。 本当は業務で必要になって土日に勉強しただけだが…。
- 作者: Rob Story,Matt Davis
- 出版社/メーカー: O'Reilly Media
- 発売日: 2016/12/25
- メディア: ペーパーバック
- この商品を含むブログを見る
【改訂新版】[オープンデータ+QGIS]統計・防災・環境情報がひと目でわかる地図の作り方
- 作者: 朝日孝輔,大友翔一,水谷貴行,山手規裕
- 出版社/メーカー: 技術評論社
- 発売日: 2018/12/28
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
folium
pythonに地図表示ライブラリのfoliumというのがあったのでこちらを使ってみた。
python-visualization.github.io
これはブラウザ上でいろんなレイヤを作成するライブラリなので、 基本的にはhtml/css/svgを吐き出す装置だと思ってくれればよい。
使い方
一般的には下記の使い方手順。
マップを作成する(キャンバスのようなもの)
権利とかにうるさくないopenstreetmapで生成が基本
地図の上に表示したいものを追加する
線とか、アイコンとか、ポリゴンとか
表示する or 保存する
jupyter notebookを使っていればノートブックに表示もできるし、 htmlを出力して別途使うことができる。
表示するデータ
今回は山手線の駅と東海道新幹線の駅をAさんとBさんが歩いてみたことにする。
とてもこんな速度で歩けるとも思えないが…。
人 | 日時 | 緯度 | 経度 |
---|---|---|---|
A | 2019/2/22 12:00 | 35.619700 | 139.728553 |
A | 2019/2/22 12:30 | 35.626446 | 139.723444 |
A | 2019/2/22 13:00 | 35.626446 | 139.723444 |
A | 2019/2/22 13:30 | 35.633998 | 139.715828 |
A | 2019/2/22 14:00 | 35.633998 | 139.715828 |
… | … | … | … |
B | 2019/2/22 12:00 | 35.681382 | 139.766084 |
B | 2019/2/22 12:30 | 35.655767 | 139.753262 |
B | 2019/2/22 13:00 | 35.655767 | 139.753262 |
B | 2019/2/22 13:30 | 35.630152 | 139.740440 |
B | 2019/2/22 14:00 | 35.630152 | 139.740440 |
… | … | … | … |
こんなデータの持ち方をしているとする。
表示の仕様
2種類やるとする。
一枚に2つの移動を色を変えて表示
ついでに各線をクリックするとポップアップで誰が通ったのかも表示する
一人に一枚の地図を用意し、それをhtmlに保存し、画像にも保存する。
一枚に2つの移動を色を変えて表示
さて、コーディング
# あとで使うライブラリも併せて読み込み import os import folium import pandas as pd from time import sleep as slp from selenium import webdriver import glob from selenium.webdriver.chrome.options import Options # csvをpandas dataframeに保存 data = pd.read_csv("./gps.csv",encoding="shift_jis") # 今回はA,Bの人しか居ないが、 # 一応何人来てもいいように人のリストを作り、 # それをforループで回す person_list = data["人"].unique() # 地図に表示する色 # foliumでサポートしているのは下記19色 color_list=['red','blue','green','purple','orange','darkred','lightred','beige','darkblue','darkgreen','cadetblue','darkpurple','white','pink','lightblue','lightgreen','gray','black','lightgray'] # 地図オブジェクトを作成 m = folium.Map(tiles='OpenStreetMap') for idx,person in enumerate(person_list): # 一人分のデータだけをdata_tempに格納する data_temp = data[data["人"] == person] # data_tempの順番を日時で昇順ソート data_temp = data_temp.sort_values('日時', ascending=True) # data_tempの緯度経度だけを data_temp_lat_lon = data_temp[["緯度","経度"]] # 緯度経度を配列に格納 locs = data_temp_lat_lon.values # 色を指定 line_color = color_list[idx%len(color_list)] # 地図に線を追加する。緯度経度の配列をそのまま線として使う folium.PolyLine(locs,color=line_color,popup=person).add_to(m) # 地図の表示範囲を緯度経度の最低最大とする m.fit_bounds([[data["緯度"].min(),data["経度"].min()], [data["緯度"].max(),data["経度"].max()]]) # 地図を表示する m
そうするといい感じに表示されます。
一人に一枚の地図を用意し、それをhtmlに保存し、画像にも保存する
さて、こちらのほう。
htmlに保存するところまではfolium側でメソッドが用意されています。
m = folium.Map(tiles='OpenStreetMap') m.save("hoge.html")
で保存できるのですが、
そこで表示される画像を保存したい、だとfoliumだけでは対応できません。
そこで、ご存知seleniumを使ってスクショを取って保存を使いました。
さて、コーディング(続き)
for person in person_list: # 一人分のデータだけをdata_tempに格納する data_temp = data[data["人"] == person] # data_tempの順番を日時で昇順ソート data_temp = data_temp.sort_values('日時', ascending=True) # data_tempの緯度経度だけをデータフレームに残す data_temp_lat_lon = data_temp[["緯度","経度"]] # 地図オブジェクトを生成 m = folium.Map(tiles='OpenStreetMap') # 緯度経度を配列に格納 locs = data_temp_lat_lon.values # 地図に線を追加する。緯度経度の配列をそのまま線として使う folium.PolyLine(locs).add_to(m) # 地図の表示範囲を緯度経度の最低最大とする m.fit_bounds([[data_temp["緯度"].min(),data_temp["経度"].min()], [data_temp["緯度"].max(),data_temp["経度"].max()]]) # htmlに保存する # ./html/xx.htmlに保存される m.save(outfile="./html/"+person+".html") # seleniumでブラウザを開く browser = webdriver.Chrome() # 画面を最大化 browser.maximize_window() # URLを指定(ローカルファイル) tmpurl="file:///./html/" + person + ".html" # URLを開く browser.get(tmpurl) # 一応3秒寝かす slp(3) # スクリーンショットを取る browser.save_screenshot("./png/"+person+".png") # ブラウザを閉じる browser.quit()
そうするといい感じに画像を保存してくれる。
ちなみに線ではなくMarkerやCircleで表示したい場合は、
folium.PolyLine(locs).add_to(m)
の部分を
for loc in locs: folium.Circle(loc).add_to(m)
ないし
for loc in locs: folium.Marker(loc).add_to(m)
にするとよろし。
これをまたパワポに自動で貼り付けるというのもやったのだが、それはまた別の話。