
Pythonを使ってジオコーディング 緯度経度情報を取得してマップに表示する
何で緯度経度が知りたいかって?
別にいいじゃないか。悪いことを企んでいる訳ではないのだから。
出来るのか?
ここだけの話、正直に打ち明けると、数十件の住所リストの場所を地図にマーカーを付けるという作業が必要になって、Pythonなら簡単にできるんじゃね? と思ったのがきっかけ。
なぜそんなに地図マーカー打たなきゃならいの? って聞くのは野暮ですよ。
地図に1つのマーカーを打つなら、単にgoogle mapで検索するだけでいい。
例えば「東京スカイツリー」と検索すれば、こんな風にマーキングされますよね。でも一度にたくさんの場所にマーカーを打つことは出来ない。
という訳で、まずは「python 地図 表示」という検索ワードで検索してみれば、たくさんの検索結果が出てくる。
どうやら、foliumという地図表示用ライブラリがあるらしい。つまり、出来そうだということだ。出来そうだと分かれば出来たようなものだ。
と、ここまでは順調だった(google検索しただけだが)。
地図にマーキングする際には、緯度経度、つまりその場所の座標が必要だ。例えばPCの場合、先程の東京スカイツリーをマウスで右クリックすれば下図の「35.71017, 139.81067」というように見ることが出来る。コピペも出来る。
数件しらべるだけならこのような手作業でも良いが、件数が多くなるとだいぶだるい。なので誰かにやってもらいた。けれど頼めるような友人はいない。お金も払いたくない。
となればPythonさんに頼むしかない、となるのである。
Pythonで緯度経度を取得する その1
で、「python 緯度経度」で検索すると下記サイトが見つかる。
いいじゃん。こんな便利な備忘録を公開してくれるなんて、神!
さっそく、やってみると・・・。めちゃくちゃ遅い。あっという間にやってくれるものと思っていたのがいけないのだが、数十件でこの遅さならもっと数が増えたらとても使えないなと思った。
でも、よく読めば書いてあった。
よく読めよ! って話です。
API提供元に迷惑ってどういうことだと思って、geocoding.jpのページを見てみると、
Geocodingのページ
注意書きを拡大してみると、
赤字で2回も書かれていた。検索を10秒程度に1回に抑えてくださいと。しかも、個人で運用しているサイトだというではないか。すごい人がいるもんです。遅いなって文句言った私がアホでした。
とは言え、気が短い私は最初の1回は待てたが、作業や住所の間違いなどがあって度々やり直す必要が出てきて、すぐに待てなくなった。
じゃあ、どうしたかというと、いろいろやって見ました。こちらを見て、国土地理院のAPIを使ってみたり、google mapのURL表示欄に記載される位置情報が使えないか探ってみたり(下図)。
でも、どれもピンポイントで示す緯度経度が得られない。少しずれちゃうんですよ。
Pythonで緯度経度を取得する その2
で、結局のところ採用したのは、Google Map API を使うという一番無難な方法。個人利用だし、一度きりだし、無料枠内で済むことは明らかなので。
登録にはクレジットカードが必要だし、使うまでの手順が少々面倒くさいが、公式ガイドを追っかけながら進んでいき、APIのキーが得られてしまえば、こちらに掲載されていたサンプルコードそのものでいける。
import googlemaps
MAPS_API_KEY = 'GOOGLE_MAPS_API_KEY'
def geocode(address):
try:
gmaps = googlemaps.Client(key=MAPS_API_KEY)
result = gmaps.geocode(address)
lat = result[0]['geometry']['location']['lat']
lng = result[0]['geometry']['location']['lng']
return lat, lng
except:
return None, None
(noteだとコードに色がつかないのかな? 下書きでは付かないけど投稿すると色がつくのね)
簡単そうなんで、これを借用して下記のようなコードを作りました。
もちろん作ったなどと胸を張って言えるレベルではない。動けばいいやレベル。
from glob import glob # ファイルパス用
import pandas as pd # Excel読み書き用
from tqdm import tqdm # プログレスバー表示用 pip install tqdm
import googlemaps # Google Map用 pip install googlemaps
MAPS_API_KEY = 'GOOGLE_MAPS_API_KEY'
def geocode(address):
try:
gmaps = googlemaps.Client(key=MAPS_API_KEY)
result = gmaps.geocode(address)
lat = result[0]['geometry']['location']['lat']
lng = result[0]['geometry']['location']['lng']
return lat, lng
except:
return None, None
#---------------------------------------------
# 住所リストを読み込む
# 住所リストには address というカラムが必須
filepaths = glob('address.xlsx')
filepath = filepaths[0]
df = pd.read_excel(filepath)
# 緯度経度データの取得
result = [] # 取得した緯度経度を入れておくリスト
for ad in tqdm(df['address']):
result.append(geocode(ad))
# 取得したデータの保存
_df = pd.DataFrame(result, columns=['altitude', 'longitude'])
df = df.join(_df)
df.to_excel('address_with_altlong.xlsx', index=False)
住所リストから緯度経度情報を取得して保存するコード
5行目の、MAPS_API_KEY = 'GOOGLE_MAPS_API_KEY' のところは自分で取得したキーに入れ替えてねということ。
このソフトと同じディレクトリに、Excelで作った住所リスト「address.xlsx」を入れて実行すると、緯度経度を取得して「address_with_altlong.xlsx」というファイルに保存してくれるというもの。
試しに、下のようなリストを作ってみた。東京湾から臨める4大タワーですね(笑)。
これを先のコードと同じディレクトリに入れて実行すると1秒くらいで座標が得られた。
マップにマーキング
取得できた緯度経度情報を元に、冒頭に掲載したサイトに書かれているようなページや、こちらのようなページをみながら、これまた動けば良いレベルでつくってみたのが、こちら(動作することを保証はしませんよ)。
map_location.htmlとしてマップが保存されます(ローカルに)。
import pandas as pd
from glob import glob
import folium
from folium.features import DivIcon
# 地図のポップアップ文字を横書きにする
def yokogakika(t):
popup_text = '<span style="white-space: nowrap;">' + t + '</span>'
return popup_text
# 地図のマーカーを丸数字にする
# 返り値をfoliumのicon=の後に指定する
def MakeMaruMarkerHtml(num, diam):
out_text = '''<div
style="
text-align: center;
font-size: 11pt;
color : black;
background: green;
width: {}px;
height: {}px;
border:2px solid #666;
border-radius: 50%;
"
>'''.format(diam, diam)
out_text += str(num) + '</div>'
return out_text
def yenstr(num):
text = "¥{:,}".format(num)
return text
#----------------------------------------------------MAIN
filepaths = glob('address_with_altlong.xlsx')
filepath = filepaths[0]
df = pd.read_excel(filepath)
# 緯度経度の中心点を計算
df_altlong = df.loc[:, 'altitude':'longitude']
mean_address = df_altlong.mean(axis=0)
zoom = 10
map = folium.Map(mean_address, zoom_start=zoom)
# マップにプロットする
for i, r in df.iterrows():
num_name = str(r['num']) + ' ' + r['name']
folium.Marker(
location=[
r['altitude'],
r['longitude']],
popup=yokogakika(num_name),
icon=DivIcon(
icon_size=(25, 25),
icon_anchor=(0,0),
html=MakeMaruMarkerHtml(r['num'], 25)
)
).add_to(map)
map.save('map_location.html')
マップにプロットするコード
結果がこちら(下図)。
添付したファイルをダウンロードすればブラウザで見れます(きっと)。
マーカーをクリックすると番号と名称が表示されます。
(上に表示されている地図はスクショ画像なので、ダウンロードしたファイルをブラウザで表示して下さい。というかnoteには直接貼り付け出来ないのかしら)
出来ましたね。
おわり