茨の道も一歩から

インフラ構築からプログラミング(Python・JavaScript)までITに関するブログです。

ipyleafletによる人流分析をマップ上に表示させてみる

人流分析

  • SoftWareDesign (2020年4月号)に、興味をそそる記事があり試してみました。
  • Jupyter Notebook上で、疑似人流分析データをマップ表示させる

f:id:sireline:20200705155117p:plain

疑似人流データの取得

記事のGitHub

Pythonパッケージ

仮想環境構築

  • pip installしたパッケージ
ipyleaflet
numpy
pandas
matplotlib

Pythonコード

csvファイルを読み込んで、1件のデータを表示

import numpy as np
import pandas as pd
import datetime as dt


df = pd.read_csv('2013_12_24.csv')
df.iloc[:,2] = pd.to_datetime(df.iloc[:,2])
df.iloc[:,4] = df.iloc[:,4].astype(float)
df.iloc[:,3] = df.iloc[:,3].astype(float)

print( df.iloc[ 1, : ] )

出力結果

uid                            1
gender                         1
timestamp    2013-12-24 01:00:00
lat                      35.1707
lon                      136.882
cat1                      travel
cat2               Train Station
STAY_MOVE                   STAY
cat_id                         2
Name: 1, dtype: object

ある期間の人流データを取得

humans = df[(dt.datetime(2013, 12, 24, 7, 0) < df.iloc[:,2]) &
            (df.iloc[:,2] < dt.datetime(2013, 12, 24, 9, 0))]
print(humans)

出力結果

         uid  gender           timestamp        lat         lon  cat1  \
74         1     1.0 2013-12-24 07:05:00  35.170274  136.880557   NaN   
75         1     1.0 2013-12-24 07:10:00  35.170274  136.880554   NaN   
76         1     1.0 2013-12-24 07:15:00  35.170273  136.880552   NaN   
...      ...     ...                 ...        ...         ...   ...   
140842  1467     NaN 2013-12-24 08:45:00  35.483186  137.519981   NaN   
140843  1467     NaN 2013-12-24 08:50:00  35.485364  137.516451   NaN   
140844  1467     NaN 2013-12-24 08:55:00  35.487892  137.512969   NaN   

             cat2 STAY_MOVE  cat_id  
74            NaN      MOVE     NaN  
75            NaN      MOVE     NaN  
76            NaN      MOVE     NaN  
...           ...       ...     ...  
140842        NaN      MOVE     NaN  
140843        NaN      MOVE     NaN  
140844        NaN      MOVE     NaN  

[8946 rows x 9 columns]

緯度、経度、ズームサイズ、ベースマップを指定してマップ表示

from ipyleaflet import *
from ipyleaflet import Map, FullScreenControl

center = (35.1707, 136.882)
m = Map(center=center, zoom=15, basemap=basemaps.OpenStreetMap.Mapnik)
m

f:id:sireline:20200705161749p:plain


「人の位置」をマップに表示

points = []
for row in humans.itertuples(name=None):
    points.append(Circle(location=(row[4], row[5]),radius=150, fill=True, fill_opacity=0.3, stroke=False))
for point in points:
    m.add_layer(point)

m

f:id:sireline:20200705164526p:plain


特定の人物の移動した経路をアニメーション表示

aPerson = df[df.iloc[:,0]==1015]
locs = []
ant_paths = []
for row in aPerson.itertuples(name=None):
    locs.append([row[4], row[5]])
ant_paths.append(AntPath(locations=locs, use='polyline'))
m += ant_paths[-1]

f:id:sireline:20200705155117p:plain


特定条件に応じた「人々の位置頻度分布」の重ね合わせ表示

%matplotlib inline
import matplotlib.pyplot as plt

# 人の存在頻度を描画する、緯度経度範囲を定義
right = max(humans.iloc[:,4])
left = min(humans.iloc[:,4])
top = max(humans.iloc[:,3])
bottom = min(humans.iloc[:,3])

# 人の存在頻度を2Dヒストグラムとして描く
plt.figure( figsize=(15, 15), dpi=500 )
fig, ax = plt.subplots( figsize=(5, 5), dpi=100 )
ax.hist2d( humans.iloc[:,4], humans.iloc[:,3], 
           bins=[  np.linspace( left,   right, 200 ),
                      np.linspace( bottom, top,   200 )],
           cmap=plt.cm.jet )
ax.grid( False ); ax.axis('off')
# matplotlibレンダリング結果を画像(image)に格納
fig.canvas.draw()
image = np.array( fig.canvas.renderer._renderer )

#  Python 2と3で、ストリームを扱うモジュールが
# 違うため、それぞれに応じたストリーム定義にする
from base64 import b64encode; import PIL
try:
    from StringIO import StringIO
    py3 = False
except ImportError:
    from io import StringIO, BytesIO
    py3 = True
if py3:
    f = BytesIO()
else:
    f = StringIO()
# 作成した2次元画像を、地図に重ねて描画する準備
im = PIL.Image.fromarray( image ); im.save( f, 'png' )
data = b64encode( f.getvalue() )
if py3:
    data = data.decode( 'ascii' )
imgurl = 'data:image/png;base64,' + data
bounds = [ (bottom, left), (top, right) ]
io = ImageOverlay( url=imgurl, bounds=bounds )
m.add_layer( io )                            # 画像をレイヤーに追加
io.interact( opacity=( 0.0, 1.0, 0.01) ) # 透明度を可変にする

f:id:sireline:20200705155212p:plain


おわりに

  • どこかのサイトで混雑状況をマップ表示していたのを見て気になっていたので、すっきりした。
  • SoftWare Designは、ITエンジニアにとって有用な記事が多いので、おすすめ。

amzn.to