【Python】foliumで時系列位置情報を可視化する方法(ヒートマップ・GIF)

プログラミング

Pythonのfoliumライブラリで位置情報を可視化できることを学んだけど、時系列データを地図上にマッピングして時間推移を見えるようにしたい。何かいい方法はないかな。。

こんな悩みにお答えします。

実は、foliumのメソッドを用いたりGIF化を行うことで実現できます。

今回は、foliumで時系列位置情報を可視化し、時間推移を見える化する方法をご紹介します。

この記事を読み終えると、foliumを用いて時系列データの可視化を自由に行うことができるようになります。

本記事の内容
・時系列位置情報を可視化し、時間推移を見える化する方法
・foliumライブラリの利用方法
・pngファイルのGIF化方法

>>【Python】位置情報(緯度・経度)を可視化する方法(答えはfoliumライブラリ)
>>【Python】foliumのマーカーアイコンを自由に変更する方法

Pythonを学べるおすすめのプログラミングスクール
1. Aidemy
・・・AIエンジニアとしてのスキルを身に付けたい。その延長で就職、転職できたら嬉しい方におすすめ。
2.侍エンジニア塾
・・・基礎力と即戦力を身に付けられる、満足度No.1スクール
3.
TechAcademy
・・・副業に向けてスキルアップしたい。フリーランスなどを目指している方向け。
4
. AIジョブカレッジ
・・・コスパ良く、質の高い講座を受けたい方におすすめ。

本記事の信頼性

ひよこ
ひよこ

私は、大学時代にプログラミングを学び、PHPなどのWeb系言語からAIに用いられるPythonまで幅広く経験してきました。

現在はデータサイエンティストとして大企業で活動しています。

また今ではほぼ不労所得として月10万円以上の収益を継続的に達成しています。

 

1. 時系列データを可視化する方法

位置情報の時系列データを可視化する方法は大きく2種類あります。

  1. foliumメソッドを利用してヒートマップを作成する方法
  2. 1枚1枚画像を作成し、最後に繋ぎ合わせてGIF化する方法

    それぞれ少しずつ用途が異なるため、あなたのユースケースに合わせて参考いただければと思います。

     

    完成イメージは以下のとおりです。

    1. foliumメソッドを利用してヒートマップを作成する方法

     

    2. 1枚1枚画像を作成し、最後に繋ぎ合わせてGIF化する方法

     

    2.実行環境

    以降、実際にコーディングしていく上で、実行環境を記載いたします。

    • Windows10
    • Python:3.6.4
    • folium:0.12.1
    • selenium:3.141.0
    • PIL:8.3.1

     

    3. foliumメソッドを利用してヒートマップを作成する方法

    まずはfoliumメソッドを利用してヒートマップを作成する方法です。

    a. 方法と特徴

    ヒートマップを作成する場合、folium.plugins.HeatMapWithTime()を利用します。データと時間を指定することで簡単にヒートマップで可視化することができます。

    foliumのメソッドを利用する方法の特徴は

    • 円のサイズやスケール(ヒートマップの色度合い)を自由に変更できる
    • foliumのメソッドであるため容易に実装できる

    などが挙げられます。

    一方で、データ形式に特徴があるため前処理の段階でデータを整形してあげる必要があります(詳細は次項)。

    b. サンプルデータ

    今回は簡単のため、サンプルデータは手動で作成しております。

    data = [
       [[35.660126,139.697719,0.3]],
       [[35.659012,139.703387,0.5]],
       [[35.658034,139.701636,0.8]],
       [[35.657034,139.69636,0.95]]
    ]

    ヒートマップを作成する際のデータ形式は上記のような3次元データです。内訳は以下のとおり。

    表示する時間×特定時刻におけるデータ×データ(緯度、経度、スケール)

    各次元データ概要
    表示する時間時系列分のデータを格納します。上記例では4時刻分データがあり可視化した際に4段階の移動が表示されます。
    特定時刻におけるデータ上記例では各時刻とも1つのデータしか格納しておりませんが、データ数に応じて複数のデータが格納されます。
    データ(緯度、経度、スケール)緯度・経度は必須、スケールは任意になります。またスケールはヒートマップの色合いに影響するため0~1に正規化しておく必要があります。

     

    c. サンプルコード

    import folium
    from folium import plugins
    import datetime
    
    #ヒートマップを作成する関数
    def map_view(data,time_index,map_file="default"):
       #ベースとなるマップを作成。渋谷近辺
       map = folium.Map([35.658034, 139.701636], zoom_start=15,tiles="Stamen Terrain")
       hm = plugins.HeatMapWithTime( #ヒートマップを作成
          data,
          index=time_index, #時刻指定
          auto_play=True,
          radius=30, #ヒートマップの大きさ
          max_opacity=0.3,
          gradient={0.1: 'blue', 0.25: 'lime', 0.5:'yellow',0.75: 'orange', 0.9:'red'}#色度合い指定
       )
       hm.add_to(map)
    
       map_file = map_file + ".html"
       map.save(map_file) #作成したマップを保存
    
    #サンプルデータ
    data = [
       [[35.660126,139.697719,0.3]],
       [[35.659012,139.703387,0.5]],
       [[35.658034,139.701636,0.8]],
       [[35.657034,139.69636,0.95]]
    ]
    
    #表示する時刻(サンプルデータのデータ数と一致している必要あり)
    time_index = [
       datetime.time(20, 31, 0, 0).strftime("%H:%M:%S"),
       datetime.time(20, 38, 0, 0).strftime("%H:%M:%S"),
       datetime.time(20, 40, 0, 0).strftime("%H:%M:%S"),
       datetime.time(21, 26, 0, 0).strftime("%H:%M:%S")
    ]
    
    #heatmap_1として可視化・保存
    map_view(data,time_index,map_file="heatmap_1")

    こちらのコードを実行した結果は以下のとおり。

     

    4つのデータの時間推移が確認でき、時刻も指定した通りに記載されています。ヒートマップ中の繰り返しボタンを押した上で再生ボタンを押下すると連続して時間推移を確認することができます。

     

    また、以下のように緯度、経度のみのデータを用意した場合も実行してみます。

    data = [
       [[35.660126,139.697719]],
       [[35.659012,139.703387]],
       [[35.658034,139.701636]],
       [[35.657034,139.69636]]
    ]

    結果は以下のとおり。色合いがすべて統一されていることが分かります。あなたの用途次第ではスケールを用意しなくても十分というケースもあると思います。あなたの目的に合わせて実行してみてください。

     

     

    4. 1枚1枚画像を作成し、最後に繋ぎ合わせてGIF化する方法

    次に各時刻ごとに像を作成し繋ぎ合わせることでGIFを作成する方法です。

    a. 方法と特徴

    この方法では、以下の流れでGIF化していきます。

    1. folium.Marker()を利用してマーカーをプロットし特定時刻におけるマップを作成
    2. これを全時刻分繰り返し、それぞれhtmlファイルを作成
    3. htmlファイルをスクリーンショットしpngファイルを作成
    4. pngファイルを繋ぎ合わせGIF作成

    特徴としては、folium.Marker()を利用するためマーカーのアイコンを自由に変更できることです。したがって、特定の人物の移動軌跡を作成することができるようになります。

    一方で、処理工程が多く複雑のため作業時間がかかってしまうことが難点です。

    今回はこちらの記事を参考にさせていただきました。

    b. サンプルデータ

    ここでは特定人物の移動を可視化するために以下のようなExcelファイル(sample.xlsx)を用意しました。ヒートマップとの差分としてはスケールを記載していない部分が大きいかと思います。

    time                  name   lat         lon
    2018/10/31,20:31:00  gojo   35.660126   139.697719
    2018/10/31,20:38:00  gojo   35.659012   139.703387
    2018/10/31,20:40:00  gojo   35.658034   139.701636
    2018/10/31,21:26:00  gojo   35.657034   139.69636
    ひよこ
    ひよこ

    例のごとく、「呪術廻戦」より五条先生にご協力いただいております。

    c. サンプルコード

    処理ごとに記述していきます。

    c-1. 特定時刻におけるマップを全時刻分作成

    import folium
    import datetime
    from folium.features import CustomIcon
    from IPython.display import Image
    import pandas as pd
    
    #ベースとなるマップを作成する関数
    def base_map():
       map = folium.Map(
          [35.66256010486336, 139.7016042283173],
          tiles="Stamen Terrain",
          zoom_start=15
       )
       return map
    
    #アイコンを作成する関数
    def get_image(img_name):
       icon = CustomIcon(
          icon_image = img_name,
          icon_size = (55, 65),
          icon_anchor = (30, 30),
          popup_anchor = (3, 3)  
       ) 
       return icon
    
    #マップを保存する関数
    def save_map(map,map_file="default"):
       map_file = map_file + ".html"
       map.save(map_file)
    
    #アイコンを表示する関数
    def character_view(map,img_name,icon_latlon,popup):
       icon = get_image(img_name)
       folium.Marker(location = icon_latlon,icon = icon,popup=popup).add_to(map)
    
    #特定時刻のマップを作成し保存する関数
    def specific_map_view(data,map,start,end,span):
       forcus_time_st = start
       forcus_time_ed = start + span
       k = 1
       while True:
          forcus_data = data[data['time'] < forcus_time_ed]
          forcus_data = forcus_data[forcus_data['time'] >= forcus_time_st]
          if len(forcus_data) >=1:
             for i in range(len(forcus_data)):
                img_name = "./pic/" + str(forcus_data[i:i+1]["name"].values[0]) + ".png"
                icon_latlon = forcus_data[i:i+1][["lat","lon"]].values.reshape(-1).tolist()
                character_view(map,img_name,icon_latlon,forcus_data[i:i+1]["name"].values[0])
          save_map(
             map,
             map_file="./pic/default_"+str(forcus_time_st.hour)+"_"+str(forcus_time_st.minute)+"_sample"
          ) 
          forcus_time_st = forcus_time_ed
          forcus_time_ed = forcus_time_ed + span
          map = base_map()
          k += 1
          if forcus_time_ed > end:
             break
    
    if __name__ == '__main__':
       try:
          latlon = pd.read_excel(
             './sample.xlsx',
             header=0,
             index_col=None,
             engine='openpyxl'
          )
          latlon['time'] = pd.to_datetime(latlon['time'], format="%Y/%m/%d,%H:%M:%S")
    
          map = base_map()
          start = datetime.datetime(2018, 10, 31, 20, 30, 0, 0)
          end = datetime.datetime(2018, 10, 31, 21, 40, 0, 0)
          span = datetime.timedelta(minutes=5)
          specific_map_view(latlon,map,start,end,span)
    
       except Exception as e:
          print(e)

    汎用性の高い形にするために、時間を区切ってマップを作成できるように設計しています。

     

    上記プログラムを実行した結果4つのファイルが作成されます(20_30は20:30~20:35までの時間幅を表しています)。

    • default_20_30.html
    • default_20_35.html
    • default_20_40.html
    • default_21_25.html

    一例としてdefault_20_30.htmlの結果を確認すると以下のとおりです。

     

     

    c-2. htmlファイルのスクリーンショットを取りpngファイル作成

    続いて、作成した4つのhtmlファイルのスクリーンショットを取っていきます。ここではseleniumライブラリのwebdriverを使用します。

    webdriverを用いることでPython上でブラウザを操作できるようになります。詳細は割愛しますが、pipでインストール可能です。

    $pip install selenium

    サンプルコードは以下のとおりです。

    import os
    import glob
    from selenium import webdriver
    from datetime import date
    import datetime
    import time
    
    files = glob.glob("./pic/sample/*") #作成したhtmlファイル名一覧を取得
    driver_path = "./chromedriver.exe"
    delay=5
    
    for file in files:
       file = file[13:]
       tmpurl='file://{path}/pic/sample/{mapfile}'.format(path=os.getcwd(),mapfile=file)
    
       driver = webdriver.Chrome(driver_path) #Chromeでhtmlファイルを操作
       driver.get(tmpurl)
       time.sleep(delay)
    
       save = "./pic/sample/png/" + str(file[:-5]) + ".png"
       driver.save_screenshot(save) #スクリーンショットを取り、pngファイルとして保存
       driver.quit()
    ひよこ
    ひよこ

    文字列の扱いなどは置換操作を使えばもっとスマートに記述できます。ここでは汚いコードになっています。。

    c-3. pngファイルを繋ぎ合わせてGIFファイル作成

    最後にGIF化を行っていきます。サンプルコードはこちら。

    from PIL import Image, ImageDraw, ImageFont
    from datetime import datetime, date, timedelta
    import glob
    import pandas as pd
    
    im = []
    files = glob.glob("./pic/sample/png/*") #ファイル名一覧を取得
    
    #Excelファイルから時刻を取得
    latlon = pd.read_excel('./sample.xlsx', header=0, index_col=None,engine='openpyxl')
    latlon['time'] = pd.to_datetime(latlon['time'], format="%Y/%m/%d,%H:%M:%S")
    
    #1ファイルずつ追加し、時刻入力
    for i in range(len(files)):
       img = Image.open(files[i])
       draw = ImageDraw.Draw(img)
    
       #フォントはカレントディレクトリに格納
       font = ImageFont.truetype("FontsFree-Net-arial-bold.ttf", 70) #70はフォントサイズ
       text =str(latlon['time'][i].year)+"/"+
          str(latlon['time'][i].month)+"/"+
          str(latlon['time'][i].day)+" "+
          str(latlon['time'][i].hour)+":"+
          str(latlon['time'][i].minute)
       draw.text((30, 30),str(text),font=font,fill=(0,0,0))
    
       im.append(img)
    
    #全てのpngファイルを繋げてGIF化
    im[0].save(
       './pic/sample/png/sample.gif',
       save_all=True,
       append_images=im[1:],
       optimize=False,
       duration=1500, #各フレームの表示時間(ミリ秒)
       loop=0
    )

    PILを用いて複数のpngファイルからGIFを作成しています。また、時刻を記述するにあたり、こちらよりフォントをダウンロードさせていただきました。

    完成したGIFはこちら。五条先生が時刻変化に合わせて移動していることが確認できます。

     

    5. まとめ

    今回は、foliumで時系列位置情報を可視化し、時間推移を見える化する方法をご紹介しました。

    ・時系列位置情報を可視化し、時間推移を見える化する方法

    ・foliumライブラリの利用方法
    ・pngファイルのGIF化方法

    時系列位置情報を可視化し時間推移を見る方法はとても汎用性が高いです。

    位置ごとの店舗の売上高や新型コロナウイルスの新規感染者数などはヒートマップ。散策コースの可視化や軌跡推移はGIF化によって実現することができます。

    Pythonで人生を豊かにしていきましょう。

     

    本ブログでは、株式やプログラミングに関する記事を投稿しています。

    プログラミング(Python)を学びたい方におすすめの書籍やプログラミングスクール、おすすめの学習方法などをご紹介しておりますのでぜひご覧ください。

    独学で挫折してしまう方は、プログラミングスクールという方法がおすすめです。

    私の一押しは『TechAcademy』です。

    質問することですぐに分からないところをクリアにできますし、進捗をサポートしてくれるため確実に成長することができます。

    無料相談を実施しているため、まずは話を聞いてあなたのスタイルに合っているかどうか確認してみるのが良いと思います。

    スキルアップを目指したい方におすすめのオンライン学習サービス

     

    Profile
    この記事を書いた人

    現役データサイエンティスト
    【投資×プログラミング】に関するブログを運営しています。

    ■発信内容
    ・・・プログラミング(Python)、銘柄分析、株価予測など
    ■投資対象
    ・・・インデックス投資、米国ETF、米国個別株

    普段は1万人規模の大企業で世にコンテンツを生み出してます。

    ひよこをフォローする
    プログラミング開発
    ひよこをフォローする
    副業プログラミング応援団

    コメント

    タイトルとURLをコピーしました