Google Colaboratoryを使って、BODIK APIを使ったPythonプログラムを書いてみます。

課題2:地図に表示してみる

問題:BODIK APIを使って、AEDを検索し、結果を地図に表示(マーカーを表示)する。

基本情報

  • Pythonで地図を表示する場合、「Leaflet」のPythonライブラリである「folium」ライブラリが使えます。
  • Google ColaboratoryでFoliumを使うためには、foliumをインストールする必要があります。
    「!pip install folium」でインストールしてください。
  • foliumにはいくつかの関数が用意されています。
folium関数機能
folium.Mapマップを作成するmap = folium.Map(location, zoom_start)
folium.Popupポップアップを作成するpopup = folium.Popup(text, max_width)
folium.Markerマーカーを作成するmarker = folium.Marker(location, popup).add_to(map)
folium.GeoJsonGeoJsonを読み込むfolium.GeoJson(geojson).add_to(map)
foliumの主な関数

swaggerで試す

最初に、WAPIのswagger(https://wapi.bodik.jp/docs)でAPIを試してみましょう。

AED(GET /aed)のエンドポイントを表示し、「try it out」のボタンを押します。

今回は位置情報が欲しいので、いくつかのパラメータを指定します。

下の方にある青い「Execute」ボタンを押します。

検索結果が表示されます。「Request URL」のところを確認します。

パラメータ部分が変わりました。

select_type=geometry
maxResults=10
lat=33.59328962901721
lon=130.35598920962553
distance=2000

pythonで記述

では、Pythonで「BODIK API」を呼び出してみましょう。

緯度と経度を指定して、位置情報を取り出します。
位置情報は、featureの「geometry」に格納されています。

import requests
import json

api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
lat=33.59328962901721
lon=130.35598920962553
distance=2000
url = f'{api_server}/{apiname}?select_type=geometry&lat={lat}&lon={lon}&distance={distance}&maxResults=10'
response = requests.get(url)
data = response.json()
features = data['resultsets']['features']
for feature in features:
  properties = feature['properties']
  geometry = feature['geometry']
  print(json.dumps(geometry, indent=2, ensure_ascii=False))

featureのgeometryは、次のような構造になっています。

「type」が「Point」になっていますので、「coordinates」は位置情報となり、データ型は配列です。
この配列には、緯度(latitude)と経度(longitude)の数値が格納されていますが、「緯度、経度」ではなく、「経度、緯度」になっているので注意が必要です。

geometry = {
  'type': 'Point',
  'coordinates': [ lon, lat ]    # latとlonが逆になっていることに注意する
}

検索結果のgeometryから「緯度、経度」がわかるので、地図上のその場所に印(マーカーといいます)を付ければいいですね。
Pythonで地図を表示するにはどうしたらいいのでしょうか?

pythonで地図を表示

pythonで地図を表示する方法として、LeafletのPythonライブラリ「folium」を使います。

# google colabにfoliumをインストールする(1回でOK)
!pip install folium

とりあえず、地図を表示してみましょう。

import folium

# 地図の中央の緯度経度を指定する
lat = 33.59328962901721
lon = 130.35598920962553
center = [ lat, lon ]

# 地図を作成する
map = folium.Map(location=center, zoom_start=14)

# 地図を表示する
map

これだけのコードで地図を表示できました。

地図にマーカーを立てる

地図の指定した場所にマーカーを立てる方法を調べます。

# lat, lonで指定された場所にマーカーを作成する
pos = [ lat, lon ]
folium.Marker(location=pos).add_to(map)

マーカーをクリックしたときにポップアップを表示したい。

title = 'ポップアップに表示する文字列'
mypopup = folium.Popup(title, max_width=300)

# lat, lonで指定された場所にマーカーを作成する
pos = [ lat, lon ]
folium.Marker(location=pos, popup=mypopup).add_to(map)

BODIK APIと組み合わせる

地図を作成し、表示する前に、BODIK APIを呼び出すコードを追加します。

import requests
import json
import folium

# 地図の中央の緯度経度を指定する
lat = 33.59328962901721
lon = 130.35598920962553
center = [ lat, lon ]

# 地図を作成する
map = folium.Map(location=center, zoom_start=14)

# BODIK APIを呼び出す
api_server = 'https://wapi.bodik.jp'
apiname = 'aed'
lat=33.59328962901721
lon=130.35598920962553
distance=2000
url = f'{api_server}/{apiname}?select_type=geometry&lat={lat}&lon={lon}&distance={distance}&maxResults=10'
response = requests.get(url)
data = response.json()
features = data['resultsets']['features']
for feature in features:
  properties = feature['properties']
  geometry = feature['geometry']
  #print(json.dumps(geometry, indent=2, ensure_ascii=False))    # コメントアウトしておく

# 地図を表示する
map

BODIK APIの検索結果から位置情報を取り出し、地図にマーカーを立ててみましょう。

import requests
import json
import folium

# 地図の中央の緯度経度を指定する
lat = 33.59328962901721
lon = 130.35598920962553
center = [ lat, lon ]

# 地図を作成する
map = folium.Map(location=center, zoom_start=14)

# BODIK APIを呼び出す
api_server = 'https://wapi.bodik.jp'
apiname = 'aed'

# APIのURLを組み立てる
url = f'{api_server}/{apiname}?select_type=geometry&lat={lat}&lon={lon}&distance=2000'

# BODIK APIを呼び出す
response = requests.get(url)
data = response.json()
features = data['resultsets']['features']
for feature in features:
  properties = feature['properties']
  geometry = feature['geometry']

  # ポップアップを作成
  title = properties['name']
  mypopup = folium.Popup(title, max_width=300)

  # マーカーを作成
  location = geometry['coordinates']
  marker_lat = location[1]
  marker_lon = location[0]
  pos = [ marker_lat, marker_lon ]
  folium.Marker(location=pos, popup=mypopup).add_to(map)

# 地図を表示する
map

プログラム(完成版)

コメントとエラー処理を入れて完成です。
Google Colaboratoryの場合、画面出力は最後にないとうまく表示されないので、BODIK API部分だけを例外処理しています。

import requests
import json
import folium

# 地図の中央の緯度経度を指定する
lat = 33.59328962901721
lon = 130.35598920962553
center = [ lat, lon ]

# 地図を作成する
map = folium.Map(location=center, zoom_start=14)

try:
  # BODIK APIを呼び出す
  api_server = 'https://wapi.bodik.jp'
  apiname = 'aed'

  # APIのURLを組み立てる
  url = f'{api_server}/{apiname}?select_type=geometry&lat={lat}&lon={lon}&distance=2000'

  # BODIK APIを呼び出す
  response = requests.get(url, timeout=5.0)

  # APIの実行結果を確認する 
  if response is not None and response.status_code == 200:
    # 結果をJSONで取得する
    data = response.json()

    # BODIK APIの検索結果を解析する
    if data is not None and 'resultsets' in data:
      resultsets = data['resultsets']
      if 'features' in resultsets:
        features = resultsets['features']
        for feature in features:
          properties = feature['properties']
          geometry = feature['geometry']

          # ポップアップを作成
          title = properties['name']
          mypopup = folium.Popup(title, max_width=300)

          # マーカーを作成
          location = geometry['coordinates']
          marker_lat = location[1]
          marker_lon = location[0]
          pos = [ marker_lat, marker_lon ]
          folium.Marker(location=pos, popup=mypopup).add_to(map)
      else:
        print('no features', resultsets)
    else:
      print('no resultsets', data)
  else:
    print('status_code', response)

except Exception as e:
  print('Exception', e)

# 地図を表示する
map

お疲れ様でした。