よちよちpython

独習 python/Qpython/Pydroid3/termux

【geocoding jpとfolium】地名から地図を作成する

geocoding.jpを利用して緯度経度を取得してみよう


Geocoding - 住所から緯度経度を検索 にアクセスし、地名を入力して検索をかけると地名の座標(緯度と経度)が取得できる。

このサイトのAPIを使うと、Pythonからでも座標が取得できる。またfoliumというライブラリを使うとOpenStreetMapで地図が作成できる。
この2つを使い、座標にピンを差した地図を作成する。



GoogleマップAPIを使う手もあるが、登録してAPIキーを入手する必要があるので、今回は見送った。

geocoder というライブラリを使っても簡単に地名から座標が取得できるが、日本の地名からの座標取得は精度が悪かったので今回は geocoding.jp を使いました。

作業環境


  • Androidスマホ
  • termux
  • Python3.8
  • JupyterNotebook
  • 外部ライブラリ
    • requests(座標取得用)
    • BeautifulSoup4(同上)
    • tqdm(同上)
    • Pandas(同上、地名一覧作成用)
    • folium(地図作成用)



目次




外部ライブラリは下記のような方法で環境に合わせて先にインストールしておきます。

$ pip install requests beautifulsoup4 t
qdm folium pandas



座標取得


座標取得関数

こちらのサイト様の写経です。ありがとうございます。

ここでは、geocoding.jpAPIを利用して座標を取得する関数を定義している。引数に住所や地名の渡します。戻り値は座標(緯度と経度)のリスト。

import requests
from bs4 import BeautifulSoup
import time
from tqdm import tqdm


def get_lat_lon_from_address(address_l):
    """
    address_lにlistの形で住所を入れてあげると、latlonsという入れ子上のリストで緯度経度のリストを返す関数。
    >>>>get_lat_lon_from_address(['東京都文京区本郷7-3-1','東京都文京区湯島3丁目30−1'])
    [['35.712056', '139.762775'], ['35.707771', '139.768205']]
    """
    url = 'http://www.geocoding.jp/api/'
    latlons = []
    for address in tqdm(address_l):
        payload = {"v": 1.1, 'q': address}
        r = requests.get(url, params=payload)
        ret = BeautifulSoup(r.content,'lxml')
        if ret.find('error'):
            raise ValueError(f"Invalid address submitted. {address}")
        else:
            lat = ret.find('lat').string
            lon = ret.find('lng').string
            latlons.append([lat,lon])
            time.sleep(10)
    return latlons

time.sleep(秒数)で一件取得ごとに10秒待ってサーバーに負担を掛けない作り。取得に少々お時間を要します。



地名データの用意

ここではPandasのread_html(url)を使って、指定のURLに載っている表を全て取得する。
そこから目当ての地名一覧を作成している。

import pandas as pd
df = pd.read_html("https://ja.m.wikipedia.org/wiki/%E7%A5%9E%E7%B1%A0%E7%9F%B3")
df[0]
名称 読み 所在地 備考
0 おつぼ山神籠石 NaN 佐賀県武雄市橘町小野原 史跡(国指定)
1 帯隈山神籠石 おぶくまやま 佐賀県佐賀市久保泉町川久保町・神埼町西郷 史跡(国指定)
2 女山神籠石 ぞやま 福岡県みやま市瀬高町大草字女山 史跡(国指定)
3 高良山神籠石 こうらさん 福岡県久留米市御井高良山 史跡(国指定)
4 雷山神籠石 らいざん 福岡県糸島市雷山 史跡(国指定)
5 鹿毛馬神籠石 かけのうま 福岡県飯塚市鹿毛 史跡(国指定)
6 御所ヶ谷神籠石 ごしょがたに 福岡県行橋市津積・みやこ町勝山大久保・犀川木山 史跡(国指定)
7 杷木神籠石 はき 福岡県朝倉市林田・穂坂 史跡(国指定)
8 石城山神籠石 いわきさん 山口県光市石城 史跡(国指定)
9 鬼城山城(鬼ノ城) おにのき(きのじょう) 岡山県総社市奥坂・黒尾 史跡(国指定)
10 大迴小迴山城 おおめぐり・こめぐりやまじょう 岡山県岡山市草ヶ部 史跡(国指定)
11 永納山城 えいのうさんじょう 愛媛県西条市河原津 史跡(国指定)
12 讃岐城山城 さぬききやまのき 香川県坂出市西庄町・府中町・川津町、飯山町 史跡(国指定)
13 播磨城山城 はりまきやまのき 兵庫県たつの市新宮町馬立・揖西町中垣内 NaN
14 唐原山城 とうばる(たうばる) 福岡県築上郡上毛町下唐原・土佐井 史跡(国指定)
15 阿志岐城(旧名:宮地岳古代山城) あしき 福岡県筑紫野市阿志岐 1999年発見 (蘆城か)
df_names = df[0].iloc[:,0]
df_names
0              おつぼ山神籠石
1               帯隈山神籠石
2                女山神籠石
3               高良山神籠石
4                雷山神籠石
5               鹿毛馬神籠石
6              御所ヶ谷神籠石
7                杷木神籠石
8               石城山神籠石
9            鬼城山城(鬼ノ城)
10              大迴小迴山城
11                永納山城
12               讃岐城山城
13               播磨城山城
14                唐原山城
15    阿志岐城(旧名:宮地岳古代山城)
Name: 名称, dtype: object



地名一覧から座標一覧を取得

ここでは、上で作った座標取得関数に地名一覧を代入することで座標一覧を取得している。

# ネットから地名一覧の座標を取得
latlng_list = get_lat_lon_from_address(df_names)
100%|██████████| 16/16 [03:26<00:00, 12.93s/it]

取得できたようなので表示。

# 取得した座標一覧の表示
latlng_list
[['33.177493', '130.057558'],
 ['33.335737', '130.334352'],
 ['33.160249', '130.513152'],
 ['33.297409', '130.574286'],
 ['33.500045', '130.21847'],
 ['33.676953', '130.734443'],
 ['33.675332', '130.930926'],
 ['33.354594', '130.824555'],
 ['33.987375', '132.040707'],
 ['34.725474', '133.762373'],
 ['34.721578', '134.023154'],
 ['33.977739', '133.05593'],
 ['34.289706', '133.889769'],
 ['34.894653', '134.528604'],
 ['33.567136', '131.160905'],
 ['33.493295', '130.563245']]

座標取得完了。全件なにかしらの数値が入っている。

地図の作成

folium というライブラリを使うと、座標から地図が作成できる。
ここでは、上で取得した座標一覧をfoliumに与え、その場所にピンを差した地図を作っている。
foliumの地図はデフォルトでOpenStreetMap というものが使われる。

import folium

# 最初の座標(マップオブジェクト作成用の座標)
latlng_1 =  latlng_list[0]

# マップ作成(マップオブジェクト作成)
map = folium.Map(latlng_1, zoom_start=6)

# ピンを差す
for name,location in zip(df_names, latlng_list):
    folium.Marker(location=location, popup=name).add_to(map)
    
map
    
Make this Notebook Trusted to load map: File -> Trust Notebook

ここまで実行すると、JupyterNotebookに作成した地図が表示される。

↓スクショ
f:id:chayarokurokuro:20200831200323j:plain


座標はバッチリ取得できている。素晴らしい!

地図のピンをクリックかタップすると、上のように地名が吹き出しで表示される。
(htmlを貼った方の地図は文字化けしますね…)

地図を保存する。

# 地図を保存
map.save("神籠石一覧地図.html")

地図が作業ディレクトリに指定のファイル名で保存された。
ファイルの拡張子を省くと、htmlで書かれたテキストファイルが拡張子無しで保存される。



参考


【使い方実践編】


地図作成ライブラリfoliumの色んな使い方がPythonコード付きで紹介されている
foliumメモ - Qiita

座標取得用の関数はこちらから写経 住所から緯度経度を取得するpythonスニペット - Qiita

Pythonでジオコーディング(Geocoder/Googlemaps) - Qiita
こちらではgeocoderとGoogleマップで座標取得の精度を比較・確認されています。

Pythonで地名から住所と座標を割り出すジオコーディングを試してみる | by shimakaze_soft | shimakaze-soft-techblog | Medium

Python: foliumでJupyter Notebookに地図を描画する - け日記

Folium: Python で地図可視化 - Tak's Notebook
アイコンの変え方などコード付きで解説

【ライブラリ等の公式ページ】


地図作成のfolium
GitHub - python-visualization/folium: Python Data. Leaflet.js Maps.

OpenStreetMap(略してOSM)の日本語サイト
OpenStreetMap Japan | 自由な地図をみんなの手に/The Free Wiki World Map

OSMの学習向け
LearnOSM

OSMの公式
OpenStreetMap



【地図をブログに貼る方法】


地図作成方法の解説ブログはたくさん見つかるが、ブログへ地図を貼る方法は見つからない。



ありがとうございました。