folium

公式サイト

インストール

py -m pip install folium

インポート

import folium

マップの描画

軌跡(Trajectory)のマップを作成した例である。(GPSdata_plotmap/GPSdata_util)

map_index += 1
sw_first = True
# Read CSV File
with open(csv_file, mode='r', encoding='utf-8') as file1:
next(file1) # Skip Header Line
list_csv_file = file1.readlines()
# Plotting
for csv_record in list_csv_file:
list_line = csv_record.replace('"','').replace('\n','').split(',')

if (sw_first == True): # First Record Create folium.Map
# Define Map
folium_figure = folium.Figure() # Default height/width=100%
folium_map.append(folium.Map([list_line[2],list_line[3]],
zoom_start=zoom,control_scale=True).add_to(folium_figure))
sw_first = False

if (list_line[4] == 'Address Not Found'):
display_name = 'Not Found'
else:
display_name = list_line[6]

folium.Marker(location=[list_line[2], list_line[3]],
tooltip=list_line[1],
popup=display_name,
icon=folium.Icon(color="blue")).add_to(folium_map[map_index])

# Display Map (Brawser Dependency)
folium_map[map_index]

# Save HTML File
output_html_file = csv_file.replace('.csv','')+'_folium.html'
folium_map[map_index].save(output_html_file)
  • foliumはplotlyと異なり、DataFrameを入力に使わない。
  • 画面への描画はブラウザーの機能に依存する。できない場合は、保存したHTMLファイルを表示する。

アニメーションマップの描画

foliumでアニメーションを作成した例である。(GPSdata_MobileClip)

厳密なJSON形式の辞書型データを作成する必要がある。

# Set duration by Input Parm
if (map_selection == 'f'): duration = "PT"+str(interval//2)+"S"
else: duration = None

print('\nDataFrame info ---> ')
print(dataframe3.info())

list_unique_uid = pd.unique(dataframe3['uid']).tolist()
print('\nUnique uid Count ---> ', len(list_unique_uid))

dataframe3['datetime'] = \
dataframe3['datetime'].apply(lambda d: pd.Timestamp(d).isoformat(sep='T'))

list_uid = dataframe3['uid'].tolist()
list_lat = dataframe3['lat'].tolist()
list_lng = dataframe3['lng'].tolist()
list_datetime = dataframe3['datetime'].tolist()

#Generate GeoJSON Format
features = [
{
"type": "Feature",
"geometry": {
"type": "MultiPoint",
"coordinates": [[list_lng[i], list_lat[i]]],
},
"properties": {
"times": [datetime],
"popup": "time="+datetime+", uid="+list_uid[i]+", \
lng="+str(list_lng[i])+", lat="+str(list_lat[i]),
"icon": "circle",
"iconstyle": {
#"fillColor": "blue",
"fillColor": folium_colors[
list_unique_uid.index(list_uid[i]) % len(folium_colors)
],
"fillOpacity": opacity,
"stroke": "True",
"radius": weight,
},
},
}
for i, datetime in enumerate(list_datetime, 0)
]

map = folium.Map(
location=[list_lat[0], list_lng[0]],
tiles='OpenStreetMap',
attr='Folium TimestampedGeoJson by ' + os.path.basename(__file__) \
+ ' (Input=' + os.path.basename(input_csv_file) \
+ ', Interval=' + str(interval) + ', Zoom=' + str(zoom) + ')',
control_scale=True,
zoom_start=zoom
)

TimestampedGeoJson(
{
"type": "FeatureCollection",
"features": features,
},
transition_time=200,
loop=False,
auto_play=True,
add_last_point=True,
#period="PT1M",
period="PT"+str(interval)+"S",
#duration="PT1M",
duration=duration,
loop_button=True,
speed_slider=True,
).add_to(map)

#map # Map display does not work.

# Output HTML File (UnicodeEncodeError fixed by asksaveasfilename)
output_html = tkinter.filedialog.asksaveasfilename(
title='Select Output HTML File Name',
initialdir=os.path.dirname(input_csv_file),
initialfile='folium_animation.html',
filetypes=[('HTML','.html')])

map.save(output_html)
  • 同じIDでDurationで指定するタイムフレームに復数のデータがある場合、復数のプロットが同時に(その時刻の表示時に)表れる。
  • そのためGPSdata_MobileClipでは、同じタイムフレームのIDごとに平均値を取って、タイムフレームに1つのプロットが出るようにしている。(平均値は別の関数func_select_between_values()で計算している。)

plotly

公式サイト

インストール

py -m pip install plotly==5.24.1 
  • バージョンを指定しなければ、最新版がインストールされる。

インポート

import plotly.express as px
  • インストールは”plotly”で行い、インポートは”plotly.express”にする。

マップの描画

軌跡(Trajectry)のマップを作成した例である。(GPSdata_plotmap/GPSdata_util)

zoom = 16.0    # Default Zoom Value
csv_file = 'currently processing csv file name'

# Read CSV File in DataFrame
df1 =pd.read_csv(csv_file)
df1.dropna(inplace=True, how='all')

fig = px.scatter_mapbox(
data_frame=df1,
lat="Lat",
lon="Lng",
hover_data=["DateTime","display_name"],
color="category",
size="StayTime",
size_max=100,
opacity=0.5,
zoom=zoom,
height=None,
width=None,
title='plotly Map of'+csv_file)
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r": 0, "t": 0, "l": 0, "b": 0})
fig.update_layout(autosize=True)
fig.show()

# Output HTML File
output_html_file = csv_file.replace('.csv','')+'_plotly.html'
fig.write_html(output_html_file)
  • 実際の使用方法は様々なので、ドキュメントを参照する必要がある。
  • plotlyはDataFrameから直接書き出すことができる。

アニメーションマップの描画

plotlyでアニメーションを作成した例である。(GPSdata_MobileClip)

print('\nStart func_mapplot_plotly()')

# dataframe1.dropna(inplace=True, how='all')

fig = px.scatter_mapbox(
data_frame=dataframe3,
animation_frame="datetime",
animation_group="uid",
lat="lat",
lon="lng",
hover_name="uid",
color="uid",
size="lat",
size_max=20,
opacity=opacity,
zoom=zoom,
height=None,
width=None,
title='Plotly Animation by ' + os.path.basename(__file__) \
+ ' (Input=' + os.path.basename(input_csv_file) \
+ ', Interval=' + str(interval) + ', Zoom=' + str(zoom) + ')'
)
fig.update_layout(mapbox_style='open-street-map')
fig.update_layout(margin={"r": 0, "t": 24, "l": 0, "b": 0})
fig.update_layout(autosize=True)
fig.show()

# Output HTML File (UnicodeEncodeError fixed by asksaveasfilename)
output_html = tkinter.filedialog.asksaveasfilename(
title='Select Output HTML File Name',
initialdir=os.path.dirname(input_csv_file),
initialfile='plotly_animation.html',
filetypes=[('HTML','.html')])

fig.write_html(output_html)

print('End func_mapplot_plotly()')
  • DataFrameから直接描画することができる。
  • 右上に凡例が表示され、IDごとにメモリーエリアが確保されるようである。そのためIDごとのデータが時間的に継続していない場合、表示がおかしくなる。
    • Current Animation Limitations and Caveats
      • Animations are designed to work well when each row of input is present across all animation frames, and when categorical values mapped to symbol, color and facet are constant across frames. Animations may be misleading or inconsistent if these constraints are not met.

scikit-mobility

ドキュメント

  1. 参照サイトはこちら
  2. 公式マニュアル

インストール

py -m pip install scikit-mobility

インポート

import skmob

TrajDataframe作成

Pandas DataFrame(下の例ではdataframe1)から作成する方法。

tdf = skmob.TrajDataFrame(dataframe1, latitude='latitude', longitude='longitude', datetime='hour', user_id='user')

Preprocessing : Trajectory Filtering

ノイズ、または外れ値とみなされるデータポイントを削除する関数である。

from skmob.preprocessing import filtering
filtered_tdf = filtering.filter(tdf, max_speed_kmh=500)
  • max_speed_kmh : 想定外速度はDefaultが500Km/hで、これを超えるポイントが削除される。
  • include_loops : True/False Short/Fast Loopを削除する。DefaultはFalse。
  • speed : Defaultは5Km/h。(Average速度がこれ以下なら削除する。)
  • max_loop : Defaultは6。
  • ratio_mac : 不明

Preprocessing : Trajectory compression

import skmob
from skmob.preprocessing import compression
# compress the trajectory using a spatial radius of 0.2 km
ctdf = compression.compress(tdf, spatial_radius_km=0.2)
  • spatial_radius_km : 圧縮後の最小距離(Km)、Defaultは0.2Km。

Preprocessing : Stops detection

Stay Locations (stops)を検出する。”minutes_for_a_stop”(分)以上同じところ(stop_radius_factor * spatial_radius_km)に留まっている場合に検出される。Stopの座標は、緯度経度のmedianになる。

“leaving_time=True”の場合、新しいカラム”leaving_datetime”が出力に追加される。

from skmob.preprocessing import detection

tdf = skmob.TrajDataFrame(dataframe1, latitude='latitude', longitude='longitude', datetime='hour', user_id='user')

stdf = detection.stay_locations(tdf, stop_radius_factor=0.5, minutes_for_a_stop=10.0, spatial_radius_km=0.1, leaving_time=True)

Preprocessing : Clustering

stay_locationsで滞在を検出したデータ(カラム”leaving_datetime”があるもの)から、異なる時間の同じ場所への訪問をクラスタリングする。訪問頻度が新しいカラム’cluster’に記載される。

ラベルは訪問頻度に応じたクラスタのランクに対応する整数になっていて、最も訪問されたクラスタはラベル0、その次に多く訪問されたクラスタはラベル1…と続く。

from skmob.preprocessing import clustering

skmob.preprocessing.clustering.cluster(tdf, cluster_radius_km=0.1, min_samples=1)

Measures : distance_straight_line

総移動距離をKmで表示する。結果は、カラムが”uuid”と”distance_straight_line”だけのDataFrameが出力される。

from skmob.measures.individual import distance_straight_line

dataframe1 = skmob.measures.individual.distance_straight_line(tdf, show_progress=True)
  • 実行が非常に遅いので、入力データを制限する必要がある。
  • 4万レコード(12MB)だと数秒で終了したが、5万レコード(15MB)では30%ぐらいから急激に遅くなった。

datetime

インポート

import datetime

現在時刻の取得

datetime.datetime.now()

UNIX時間から変換メソッド

datetime.datetime.fromtimestamp(unix_time)

datetime型のデータが返される。

datetime型から文字列への変換

UNIT時間をdatetime型にしたあと、文字列に変換する場合はdatetime型のメソッドを使う。

dt1 = datetime.datetime.fromtimestamp(unix_time)
dt1.strftime('%Y/%m/%d %H:%M:%S')

フォーマット部分の説明は以下の通り。(参照:datetime — 基本的な日付型および時間型」

ディレクティブ意味使用例注釈
%aロケールの曜日名を短縮形で表示します。Sun, Mon, …, Sat (en_US);So, Mo, …, Sa (de_DE)(1)
%Aロケールの曜日名を表示します。Sunday, Monday, …, Saturday (en_US);Sonntag, Montag, …, Samstag (de_DE)(1)
%w曜日を10進表記した文字列を表示します。0 が日曜日で、6 が土曜日を表します。0, 1, …, 6
%d0埋めした10進数で表記した月中の日にち。01, 02, …, 31(9)
%bロケールの月名を短縮形で表示します。Jan, Feb, …, Dec (en_US);Jan, Feb, …, Dez (de_DE)(1)
%Bロケールの月名を表示します。January, February, …, December (en_US);Januar, Februar, …, Dezember (de_DE)(1)
%m0埋めした10進数で表記した月。01, 02, …, 12(9)
%y0埋めした10進数で表記した世紀無しの年。00, 01, …, 99(9)
%Y西暦 ( 4桁) の 10 進表記を表します。0001, 0002, …, 2013, 2014, …, 9998, 9999(2)
%H0埋めした10進数で表記した時 (24時間表記)。00, 01, …, 23(9)
%I0埋めした10進数で表記した時 (12時間表記)。01, 02, …, 12(9)
%pロケールの AM もしくは PM と等価な文字列になります。AM, PM (en_US);am, pm (de_DE)(1), (3)
%M0埋めした10進数で表記した分。00, 01, …, 59(9)
%S0埋めした10進数で表記した秒。00, 01, …, 59(4), (9)
%f10進数で表記したマイクロ秒 (6桁に0埋めされます)。000000, 000001, …, 999999(5)
%zUTCオフセットを ±HHMM[SS[.ffffff]] の形式で表示します (オブジェクトがnaiveであれば空文字列)。(空文字列), +0000, -0400, +1030, +063415, -030712.345216(6)
%Zタイムゾーンの名前を表示します (オブジェクトがnaiveであれば空文字列)。(空文字列), UTC, GMT(6)
%j0埋めした10進数で表記した年中の日にち。001, 002, …, 366(9)
%U0埋めした10進数で表記した年中の週番号 (週の始まりは日曜日とする)。新年の最初の日曜日に先立つ日は 0週に属するとします。00, 01, …, 53(7), (9)
%W0埋めした10進数で表記した年中の週番号 (週の始まりは月曜日とする)。新年の最初の月曜日に先立つ日は 0週に属するとします。00, 01, …, 53(7), (9)
%cロケールの日時を適切な形式で表します。Tue Aug 16 21:30:00 1988 (en_US);Di 16 Aug 21:30:00 1988 (de_DE)(1)
%xロケールの日付を適切な形式で表します。08/16/88 (None);08/16/1988 (en_US);16.08.1988 (de_DE)(1)
%Xロケールの時間を適切な形式で表します。21:30:00 (en_US);21:30:00 (de_DE)(1)
%%文字 '%' を表します。%
%GISO week(%V)の内過半数を含む西暦表記の ISO 8601 year です。0001, 0002, …, 2013, 2014, …, 9998, 9999(8)
%u1 を月曜日を表す 10進数表記の ISO 8601 weekday です。1, 2, …, 7
%V週で最初の月曜日を始めとする ISO 8601 week です。Week 01 は 1月4日を含みます。01, 02, …, 53(8), (9)
%:zUTC offset in the form ±HH:MM[:SS[.ffffff]] (empty string if the object is naive).(空文字列), +00:00, -04:00, +10:30, +06:34:15, -03:07:12.345216(6)
strftime()strptime() の書式コード