こんな悩みにお答えします。
>>【Python】位置情報(緯度・経度)を可視化する方法(答えはfoliumライブラリ)
>>【Python】foliumのマーカーアイコンを自由に変更する方法
>>【Python】foliumで時系列位置情報を可視化する方法(ヒートマップ・GIF)
1. Aidemy
・・・AIエンジニアとしてのスキルを身に付けたい。その延長で就職、転職できたら嬉しい方におすすめ。
2.侍エンジニア塾
・・・基礎力と即戦力を身に付けられる、満足度No.1スクール
3. TechAcademy
・・・副業に向けてスキルアップしたい。フリーランスなどを目指している方向け。
4. AIジョブカレッジ
・・・コスパ良く、質の高い講座を受けたい方におすすめ。
本記事の信頼性
現在はデータサイエンティストとして大企業で活動しています。
1.
今回の出来上がりイメージは上記のとおりです。
呪術廻戦の渋谷事変を時系列位置情報と捉えて可視化してみました。多少位置関係や時間帯が曖昧な箇所がありますが、おおよそ原作通りかと思います。
このくらいのクオリティで自由に可視化することができれば、大抵のやりたいことはfoliumですべてできるようになるのではないでしょうか。
本ブログでは度々「呪術廻戦」のキャラクターさんにお世話になっておりましたが、今回初めてストーリーにも踏み込ませていただくため、少し原作漫画をご紹介させていただければと思います。
a. 呪術廻戦
呪術廻戦とは・・・
呪い。
辛酸・後悔・恥辱…。人間の負の感情から生まれる
禍々しきその力は、人を死へと導く。ある強力な「呪物」の封印が解かれたことで、
高校生の虎杖は、呪いを廻る戦いの世界へと入っていく…!異才が拓く、ダークファンタジーの新境地! (引用:公式HP)
芥見下々先生の原作作品。週刊少年ジャンプにて2018年より連載されている大人気漫画。昨年2021年には映画も公開され、呪術廻戦の人気は留まることを知りません。
私自身、半年前くらいからの読者でまだまだ新参者ですが、全巻読み込みアニメも見てしまうくらいにはハマっています✨
b. 渋谷事変
渋谷事変は、10巻~16巻の実に7巻分をかけて描かれた呪術廻戦の中でも大きな山の一つ。多くの戦闘シーンや人気キャラの死など大きな話題を呼びました。
舞台は東京渋谷。実在する土地・建物まで忠実に描かれており、読者は臨場感を与えられたのではないでしょうか。
渋谷という舞台の上で物語が展開されたため、位置情報の可視化のテーマには持って来いと判断いたしました!
2. 実行環境
以降、実際にコーディングしていく上で、実行環境を記載いたします。
- Python:3.6.4
- folium:0.12.1
- selenium:3.141.0
- PIL:8.3.1
3. 前準備
まずは前準備です。どのキャラクターがどこにいるのかを確認する必要があるため、正直この部分が最も時間がかかります。
・アイコン
a. Excelファイル
キャラクターごとに「いつ・どこにいるのか」の情報を記載します。カラムは以下のとおりです。
カラム | 概要 |
time | 時間 |
name | キャラクター名 |
lat | 緯度 |
lon | 経度 |
これを時間とキャラクターごとに何行も作成していきます。今回は約230行作成しました!(圧巻😝)
冒頭部分を確認すると以下のような感じ。
time | name | lat | lon |
2018/10/31,20:14:00 | nanami | 35.66381009 | 139.7022372 |
2018/10/31,20:14:00 | fushiguro | 35.6629513 | 139.7026899 |
2018/10/31,20:14:00 | ino | 35.66294972 | 139.701695 |
この作業だけは手作業に頼らざるを得ず、時間が正しいか、位置情報が誤っていないかを確認しながらひたすら積み上げていきます。
実際には可視化したときにキャラクターが被ってしまったり、位置関係に違和感を感じてしまったりすることが多いため少しずつ可視化をして緯度経度を調整して、、、の繰り返しになります。
b. アイコン
続いてアイコンです。foliumに呪術廻戦のキャラクターアイコンが入っているわけがありませんから、自分で用意する必要があります。
今回は実際の漫画やアニメからキャラクターのイメージを拝借しました。
キャラクター分イメージを用意し、地図にマッピングするために背景を透明化すれば準備OKです。後にプログラミングすることを考慮し、ファイル名をキャラクター名と一致させておきました(例:itadori.png)。
4. 処理の流れ
ここから、具体的な処理の流れをご説明します。主に以下の記事を参考に処理を進めていきます。
・すべての時間帯のpngファイルを作成
・pngファイルを繋ぎ合わせてGIF作成
a.
今回は時間帯を指定し可視化することを検討しました。理由は以下のとおり。
- キャラクターによって正確な位置と時間が把握できないことが多いから
- 細かい粒度(1分ごとなど)で可視化すると、動きの少ないファイルが大量に生成されてしまうから
実際に位置情報を収集する中で、5分と10分を使い分けて可視化することとしました。具体的な時間帯指定はこちらです。
各時間帯の可視化にはfoliumのMarker()メソッドを使用します。
b.
各時間帯を一つずつ、すべての時間帯の可視化を行います(20:00~20:10の可視化、20:10~20:20の可視化、、、)。
foliumで作成されたファイルはhtmlファイルであるため、それらのスクリーンショットを取りpngファイルを作成していきます。
ここではseleniumライブラリのwebdriverを使用します。
c.
最後に、作成されたpngファイルをすべて繋ぎ合わせることでGIFを作成します。
PILを用いて複数のpngファイルからGIFを作成しています。
5. サンプルコード
処理ごとに記述していきます。
a.
import folium
from folium import plugins
from datetime import timedelta
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=16
)
return map
#帳と伏魔御厨子の範囲を表示する関数
def tobari(map,start,end):
#帳(一般人閉じ込める)
if start >= datetime.datetime(2018, 10, 31, 19, 0, 0, 0):
folium.Circle(location = [35.659034, 139.701636],radius = 400,color = "red",fill = True ).add_to(map)
#帳(術師入れない)
if start >= datetime.datetime(2018, 10, 31, 20, 35, 0, 0) and end <= datetime.datetime(2018, 10, 31, 22, 10, 0, 0):
folium.Circle(location = [35.659034, 139.701636],radius = 350,color = "blue",fill = True ).add_to(map)
#帳(五条さん閉じ込める)
if start >= datetime.datetime(2018, 10, 31, 20, 40, 0, 0):
folium.Circle(location = [35.65961246, 139.7036947],radius = 90,color = "yellow",fill = True ).add_to(map)
#帳(一般人閉じ込める)
folium.Circle(location = [35.65961246, 139.7036947],radius = 60,color = "red",fill = True ).add_to(map)
#伏魔御厨子
if start >= datetime.datetime(2018, 10, 31, 23, 5, 0, 0) and end <= datetime.datetime(2018, 10, 31, 23, 10, 0, 0):
folium.Circle(location = [35.66109599528823, 139.6987660100766],radius = 140,color = "black",fill = True ).add_to(map)
#アイコンを作成する関数
def get_image(img_name='default.png'):
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]
tobari(map,forcus_time_st,forcus_time_ed)
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_2","lon_2"]].values.reshape(-1).tolist()
character_view(map,img_name,icon_latlon,forcus_data[i:i+1]["name"].values[0])
if forcus_time_st.minute <=9:
save_map(map,map_file="./pic/jujutu/default_"+str(forcus_time_st.hour)+"_0"+str(forcus_time_st.minute))
else:
save_map(map,map_file="./pic/jujutu/default_"+str(forcus_time_st.hour)+"_"+str(forcus_time_st.minute))
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(
'./jujutu/jujutu.xlsx',
header=0,
index_col=None,
engine='openpyxl'
) #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, 0, 0, 0) #開始時間を指定する必要あり end = datetime.datetime(2018, 10, 31, 20, 10, 0, 0) #終了時間を指定する必要あり span = datetime.timedelta(minutes=10) #時刻の間隔を指定する必要あり specific_map_view(latlon,map,start,end,span) except Exception as e: print(e)
b.
import os
import glob
from selenium import webdriver
from datetime import date
import datetime
import time
save_img_path = "./pic/jujutu_png/"
files = glob.glob("./pic/jujutu/*")
driver_path = "./chromedriver.exe"
delay=5
#一つずつhtmlファイルのスクリーンショットを取る
for file in files:
file = file[13:] #./pic/jujutu/部分を削除
tmpurl='file://{path}/pic/jujutu/{mapfile}'.format(path=os.getcwd(),mapfile=file)
driver = webdriver.Chrome(driver_path)
driver.get(tmpurl)
time.sleep(delay)
save = str(save_img_path) + str(file[:-5]) + ".png" #スクリーンショットをpngファイルとして保存
driver.save_screenshot(save)
driver.quit()
c. pngファイルを繋ぎ合わせてGIF作成
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, date, timedelta
import glob
import pandas as pd
im = []
files = glob.glob("./pic/jujutu_png/*")
latlon = pd.read_excel('./jujutu/jujutu.xlsx', header=0, index_col=None,engine='openpyxl')
latlon['time'] = pd.to_datetime(latlon['time'], format="%Y/%m/%d,%H:%M:%S")
year_text = latlon['time'][0].year
month_text = latlon['time'][0].month
day_text = latlon['time'][0].day
#pngファイルを繋ぎ合わせてGIFを作成
for i in range(len(files)):
img = Image.open(files[i])
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("FontsFree-Net-arial-bold.ttf", 70)
filename = files[i][17:]
text = str(year_text)+"/"+str(month_text)+"/"+str(day_text)+" "+str(filename[8:10])+":"+str(filename[11:13])
draw.text((30, 30),str(text),font=font,fill=(0,0,0))
im.append(img)
im[0].save(
'./pic/jujutu_png/jujutu.gif',
save_all=True,
append_images=im[1:],
optimize=False,
duration=1500,
loop=0
)
d. 作成されたGIF
改めて、こちらが作成されたGIFです。
帳(赤や青の円)が確認でき、キャラクターが移動していることも分かります。また、上部に時刻を記載することで時間推移が分かりやすくなっています。
6. まとめ
今回は、
foliumの使い方、その具体例としては最適ではないでしょうか。あなたもfoliumを使って色々なものを可視化してみましょう。
このとき大切なことは、「何ができるか」ではなく「何をしたいか」です。できることから探さずに、やりたいことをやるためにはどうすればいいかを考えていきましょう!
Pythonで人生を豊かにしていきましょう。
わたし個人としては、データ収集(作成)の難しさを痛感する機会になりました。。。
最後に、今回参考にさせていただいた資料です。
>>呪いを祓え!「呪術廻戦」とたまごっちがコラボした「じゅじゅつっち」登場
>>アニメ映画『劇場版 呪術廻戦 0』本年度 No.1 超大ヒットスタート&満足度、驚異の98%超えを記録! 七海・冥冥・京都校生らの出演情報が解禁! 日下部篤也役として声優・三木眞一郎さんが出演
>>AnimePress呪術廻戦
>>pixiv百科事辞典陀艮
>>組屋鞣造(呪術廻戦)の徹底解説・考察まとめ
>>呪術廻戦の名前や年齢や身長等、キャラのプロフィールをご紹介
>>pixiv百科事典伏黒甚爾
>>呪術廻戦の裏梅は誰?正体は何者で宿儺や五条家関連の一族か考察!何巻何話初登場かも徹底調査
>>pixiv百科事典九十九由基
>>pixiv百科事典八握剣異戒神将魔虚羅
・【株式投資】Pythonでスクリーニングする方法
・【Python】【株式投資】TA-Libによるテクニカル指標算出方法(移動平均、ボリンジャーバンド、MACD、RSI)
・【初心者向け】20分でできる!Pythonで銘柄スクリーニング結果をスマホへ通知する方法
・【Python】銘柄スクリーニング結果を定期的に通知する方法(無料)【30分でできる!】
本ブログでは、株式やプログラミングに関する記事を投稿しています。
プログラミング(Python)を学びたい方におすすめの書籍やプログラミングスクール、おすすめの学習方法などをご紹介しておりますのでぜひご覧ください。
は、プログラミングスクールという方法がおすすめです。
私の一押しは『TechAcademy』です。
質問することですぐに分からないところをクリアにできますし、進捗をサポートしてくれるため確実に成長することができます。
無料相談を実施しているため、まずは話を聞いてあなたのスタイルに合っているかどうか確認してみるのが良いと思います。
コメント