foliumでGPXファイルをマップ表示する

この記事は1年以上前に書かれました。
内容が古くなっている可能性がありますのでご注意下さい。


車載カメラとAIによる路傍の石造物調査では、GPSロガーで移動経路を記録して、石造物の位置の特定に使用しています。大量に集まったすべてのGPXファイルを一気にマップ表示するために、foliumを使う簡単なプログラムを作成しました。Python環境のあるPCで、GPXファイルをWebブラウザのマップ上に表示することができます。
実行すると、軌跡を表す青の線と、移動方向を示す黄色の▲がマップ上に描かれます。

作成したプログラムは以下のとおりです。

import folium 
from folium import plugins
import webbrowser
import gpxpy
import glob
import os

def main():
  map = folium.Map(location=[35.658099,139.741357], zoom_start=14)
  layer = folium.FeatureGroup()
  gpx_files = glob.glob("./GPSLog/*.gpx", recursive=False)
  for gpx_file in gpx_files:
    file = open(gpx_file, 'r')
    gpx = gpxpy.parse(file)
    for track in gpx.tracks:
      for segment in track.segments:        
        points = []
        for point in segment.points:
          points.append(tuple([point.latitude, point.longitude]))
        polyline = folium.PolyLine(points, popup=os.path.basename(gpx_file), color="blue", weight=3).add_to(layer)
        polyline_text = plugins.PolyLineTextPath(polyline, '   ►   ', repeat=True, attributes={'fill':'#FF0'}).add_to(layer)
  layer.add_to(map)
  map.fit_bounds(layer.get_bounds())
  map.save('map.html')
  webbrowser.open('map.html')

if __name__ == "__main__":
  main()

はじめに、foliumをはじめとする必要なモジュールをimportします。次に、

 map = folium.Map(location=[35.658099,139.741357], zoom_start=14)

でマップを作成します。中心位置の緯度経度とズームレベルを指定していますが、これは暫定的なものです。

次の

layer = folium.FeatureGroup()

で作成しているレイヤは、後で作成する複数のPolyLineを1つのレイヤとして扱うためのものです。このレイヤに合わせて、最後に中心位置とズームレベルを調整します。

フォルダ内のすべてのGPXファイルを処理するために、globモジュールを使用してファイルを列挙し、順に1つずつ開きます。ここでは、対象フォルダはカレントディレクトリ下のGPSLogという名前のフォルダとしています。

gpx_files = glob.glob("./GPSLog/*.gpx", recursive=False)
for gpx_file in gpx_files:
  file = open(gpx_file, 'r')

開いたGPXファイルには、gpxpyモジュールを介してアクセスします。GPXファイルは以下のような階層構造になっています。

<trk>
  <trkseg>
    <trkpt lat="..." lon="..." >
    </trkpt>
      :
  </trkseg>
</trk>

そこで、セグメント毎にポイントの配列を作成してPolyLineを作成します。もしもセグメント毎に分けずにすべてのポイントを含む配列を作成して1つだけPolyLineを作成すると、すべてのポイントが一筆書きでつながってしまいます。
さらに、PolyLineTextPathプラグインを使用してPolyLineに▲を重畳させて、移動方向が分かるようにします。

gpx = gpxpy.parse(file)
  for track in gpx.tracks:
    for segment in track.segments:        
      points = []
      for point in segment.points:
        points.append(tuple([point.latitude, point.longitude]))
        polyline = folium.PolyLine(points, popup=os.path.basename(gpx_file), color="blue", weight=3).add_to(layer)
        polyline_text = plugins.PolyLineTextPath(polyline, '   ►   ', repeat=True, attributes={'fill':'#FF0'}).add_to(layer)

作成したPolyLineはlayerに集めただけでmapに追加していないので、

layer.add_to(map)

でlayerをmapに追加してすべてのPolyLineを表示させます。さらに、

map.fit_bounds(layer.get_bounds())

でlayerの領域を取得して、それをmapの領域としています。これによって、すべてのPolyLineを含む領域が表示されることになります。
最後に、作成したWebページをmap.htmlファイルに保存し、既定のWebブラウザで開きます。

map.save('map.html')
webbrowser.open('map.html')

100件ほどのGPXファイルの処理には1分近くかかってしまいますが、保存されたHTMLファイルはすぐに開くことができるので便利です。