オンラインマップを利用したGeoJSONデータのプロット

Image from Gyazo

GeoJSON

これまでcsv形式のオープンデータを利用してきました,よりウェブに相性が良いデータ形式があります. それが,JSON形式(.json) です. JSONは,「じぇいそん」と読み,ブラウザで動作するプログラミング言語の JavaScript で用いられるデータ形式ですが, 現在はPythonを始めとした様々なプログラミング言語でサポートされています(Pythonでは辞書に対応する).

下記のCSV形式のデータを例に考えてみましょう.

町名,男,女,総数,世帯数
赤池町,1693,1647,3340,1315
浅田町,2593,2431,5024,2086

上記のデータをJSON形式に変換すると下記になります. JSON形式では,データは string(文字列)value(値) の組で表現されます. 例えば,“町名"という文字列と,“赤池町"という値が組になっていることがわかります. また,[ ] は配列を表しており,0番目の要素に赤池町のデータ,1番目の要素に浅田町のデータが格納されます. 要素は「,」で区切られますが,最後の要素には必要ありません.

json = [
  {
    "町名": "赤池町",
    "男": 1693,
    "女": 1647,
    "総数": 3340,
    "世帯数": 1315
  },                                                                                                                                                                                           
  {                                                                                                                                                                                           
    "町名": "浅田町",
    "男": 2593,
    "女": 2431,
    "総数": 5042,
    "世帯数": 2086
  }
]
print(json[0])
print(json[1])
{'町名': '赤池町', '男': 1693, '女': 1647, '総数': 3340, '世帯数': 1315}
{'町名': '浅田町', '男': 2593, '女': 2431, '総数': 5042, '世帯数': 2086}

このJSON形式を基本として,点,線,多角形などの空間データを表現するために用いられるのが GeoJSON 形式です. GeoJSONは,「じおじぇいそん」と読み, Leefletを始めとした様々な地図サービスで利用可能です. geojson.ioというサービスで,オリジナルのGeoJSON形式のデータを作成・共有することも可能です.

下記のCSV形式のデータを例に考えてみましょう. 緯度・経度の情報が含まれており,オンライン地図ではとして扱われます.

名称,緯度,経度,説明
休日急病診療所,35.132795,137.042009,日進市中央福祉センター内にある休日急病診療所です.
西部福祉会館,35.12599221,137.0147748,乳幼児室,学習室があります.

上記のCSV形式のデータをGeoJSON形式に変換すると下記になります. 少し複雑に見えますが,JSON形式に従っていることを確認してください. ここでは,空間データの種類を表す typePoint(点) を設定しています. Pointの他にも, LineString(線)Polygon(多角形) などを指定することもできます. また,座標は coordinates で指定していますが,経度・緯度の順番であることに注意してください. その他,名称,説明などの情報は, properties に記載します.

geojson = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry":
      {
        "type": "Point",
        "coordinates": [137.042009,35.132795]
      },
      "properties":
      {
        "名称": "休日急病診療所",
        "説明": "日進市中央福祉センター内にある休日急病診療所です."
      }
    },
    {
      "type": "Feature",
      "geometry":
      {
        "type": "Point",
        "coordinates": [137.0147748,35.12599221]
      },
      "properties":
      {
        "名称": "西部福祉会館",
        "説明": "日進市中央福祉センター内にある休日急病診療所です."
      }
    }
  ]
}
print(geojson["features"][0])
print(geojson["features"][1])
{'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [137.042009, 35.132795]}, 'properties': {'名称': '休日急病診療所', '説明': '日進市中央福祉センター内にある休日急病診療所です.'}}
{'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [137.0147748, 35.12599221]}, 'properties': {'名称': '西部福祉会館', '説明': '日進市中央福祉センター内にある休日急病診療所です.'}}

今回はGeoJSON形式に変換したオープンデータとオープンストリートマップを組み合わせ, 前回と同様のオンライン地図を作成する方法について学習していきましょう.

GeoJSONの可視化

それでは,Google Colaboratoryを利用して,GeoJSON形式のデータを可視化してみましょう.

ノートブックの作成

まずは,ノートブックを作成します. ノートブックの名前は chapter4.ipynb に設定します.

Image from Gyazo

前回利用したfoliumと,GeoJSONデータの取り込みが可能なGeoPandas,タイル地図の表示が可能なcontextilyをインストールします.

!pip install folium
!pip install geopandas
!pip install contextily
import folium
import geopandas as gpd
import contextily as cx

GeoJSON形式のデータの作成

geojson.ioを利用して,GeoJSON形式のデータを生成しましょう. 「日進市役所」をキーワードとして検索して,日進市の地図を表示してください. 画面右側にPoint(点),LineString(線),Polygon(多角形)を挿入するためのボタンがあります. このボタンを利用して,日進市役所を中心に,自由に空間オブジェクトを配置してみましょう.

Image from Gyazo

下図は日進市役所の周辺にPoint(点),LineString(線),Polygon(多角形)が配置されています.

Image from Gyazo

配置した空間オブジェクトを表すGeoJSON形式のデータは次のようになります. 変数geojsonにデータを追加していることに注意してください. 名称や説明などの情報をpropertiesに追加することも可能です.

geojson = {
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          137.03411692069665,
          35.137951224356854
        ],
        "type": "Point"
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          [
            137.04240293087713,
            35.139557898285005
          ],
          [
            137.05239739676426,
            35.13382961145339
          ]
        ],
        "type": "LineString"
      }
    },
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "coordinates": [
          [
            [
              137.0341974720302,
              35.13038180316762
            ],
            [
              137.03936555054537,
              35.128984539737644
            ],
            [
              137.0376998062303,
              35.13101056388973
            ],
            [
              137.0341974720302,
              35.13038180316762
            ]
          ]
        ],
        "type": "Polygon"
      }
    }
  ]
}

オープンストリートマップの表示

表示する地図の中心を日進市役所の緯度・経度に設定します. 緯度は35.134,軽度は137.040に設定します. また,スケール(倍率)は15に設定します.

# 日進市役所の緯度・経度
lat = 35.134
lon = 137.040

# 地図の表示
map = folium.Map(location=[lat, lon], zoom_start=15)
map

Image from Gyazo

上記で生成したGeoJSON形式のデータを,folium.Geojson()を利用して地図に追加します. 地図に作成した点や線などのデータが追加されていることを確認してください.

# 日進市役所の緯度・経度
lat = 35.134
lon = 137.040

# 地図の表示
map = folium.Map(location=[lat, lon], zoom_start=15)

# GeoJSON形式のデータを地図に追加
folium.GeoJson(geojson).add_to(map) 

map

Image from Gyazo

日進市のバス停の可視化

次に日進市のバス停のオープンデータを地図上に表示してみましょう.

データフレーム(GeoPandas)

GeoPandasを利用して,GeoJSON形式のオープンデータbus_stops.geojsonを読み込みます. これは,日進市が公開しているCSV形式のバス停のオープンデータを,GeoJSON形式に変換したファイルです.

# bus_stops.geojson
url = "https://mukai-lab.info/classes/seminar_fundamental_areas/csv/bus_stops.geojson"

# GeoJSON用のデータフレームの生成
df = gpd.read_file(url)

# HTMLで表示(=display(df)))
df

Image from Gyazo

オープンストリートマップの表示

表示する地図の中心を,全てのバス停の緯度・経度の平均に設定します. データフレームから,geometryの列を取得し,経度xと緯度yの平均を求めます. 緯度は35.1372,経度は137.0465になりました.

center_lat = df["geometry"].y.mean()
center_lon = df["geometry"].x.mean()

print(f"center_lat={center_lat} center_lon={center_lon}")
center_lat=35.1372590495031 center_lon=137.04657202546582

先に計算した緯度・経度を中心として地図を表示します. スケール(倍率)は15に設定します.

map = folium.Map(location=[center_lat, center_lon], zoom_start=15)
map

Image from Gyazo

GeoJSON形式のデータを表示するには,上述と同様にfolium.GeoJson()を用い, 引数にはGeoPandasのデータフレームを指定します. この結果,バス停がマーカーとして表示されていることを確認できます.

map = folium.Map(location=[center_lat, center_lon], zoom_start=15)

# データフレームをGeoJSON形式に変換して地図に追加
folium.GeoJson(df).add_to(map)

map

Image from Gyazo

さらに,GeoJsonTooltip()を利用して,バス停の名前をツールチップとして表示します. GeoJSON形式のpropertiesに含まれるnameプロパティを,バス停の名前として参照するよう設定します. マーカーをマウスでホバーすると,バス停の名前が表示されることがわかります.

map = folium.Map(location=[center_lat, center_lon], zoom_start=15)

tooltip = folium.features.GeoJsonTooltip(fields=["name"], labels=False)
folium.GeoJson(df, tooltip=tooltip).add_to(map)

map

Image from Gyazo

GeoPandasの活用

GeoJSON形式を読み込んだGeoPandasのデータフレームを活用すると,地理情報に関する様々な処理が可能です.

距離の算出

データフレームの各レコードから,特定の緯度・経度までの距離(単位:メートル)を算出することが可能です. ここでは,データフレームから市役所のバス停のレコードを抽出し,各バス停から市役所のバス停までの距離を算出します.

from shapely.geometry import Point

df = df.to_crs(6675)  # 直交座標系に変換

siyakusyo = df[df["name"]=="市役所"] # 市役所のレコードを抽出
point = Point(siyakusyo.geometry.x, siyakusyo.geometry.y)

df.distance(point) # 市役所までの距離を算出(単位:メートル)

Image from Gyazo

データのプロット

データフレームの緯度・経度で表された点データをグラフをして表示するには,plot()を実行するだけです. グラフの横軸が経度,縦軸が緯度になっていることが確認できます.

df = df.to_crs(4326) # 世界測地系に変換
df.plot(figsize=(10, 10))

Image from Gyazo

グラフの背景として,オープンストリートマップを表示させることができます. データフレームの座標系をWebメルカトル(EPSG:3856)に変換してから,plot()でグラフを作成します. このグラフに対し,add_basemap()でオープンストリートマップを背景に設定しています.

df = df.to_crs(epsg=3857) # Webメルカトルに変換
ax = df.plot(figsize=(10, 10))
cx.add_basemap(ax, source="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png")

Image from Gyazo

課題

Google Colaboratoryで作成した chapter4.ipynb を保存し, ノートブック(.ipynb) をダウンロードして提出しなさい. 提出の前に必ず下記の設定を行うこと.

参考書籍

愛知県名古屋市にある椙山女学園大学 文化情報学部 向研究室の公式サイトです. 専門は情報科学であり,人工知能やデータベースなどの技術要素を指導しています. この公式サイトでは,授業で使用している教材を公開すると共に, ベールに包まれた女子大教員のミステリアスな日常を4コマ漫画でお伝えしていきます. サイトに関するご意見やご質問はFacebookまたはTwitterでお問い合わせください.