2022年12月にAmazonウェブサービス (AWS)、Meta、Microsoft、TomTom によって設立されたOverture Maps Foundation (OMF)は、2023年7月26日にOMFとして最初のオープン地図データセットを公開しました 。
地図データは、ビジネスだけでなく、異常気候などの問題に取り組む際にもなくてはならないデータです。しかし、地図データの収集と維持は、莫大なコストと手間がかかります。それを世界的な企業がそろって整備し公開してくれることは、多方面で課題の解決を後押しします。
今回公開されたデータセットは、Places(場所)、Buildings(建物)、Transportation(交通網)、Administrative Boundaries(行政境界)の4つで構成されています。
なかでも特に注目すべきはPlacesデータセットです。公共施設の場所は行政から公開されることはありますが、今回のように一般のお店まで含んだデータセットが公開されることは稀です。今回は世界の約5900万もの多様な場所の位置データが公開されています。
しかも寛容なオープンデータライセンスであるCDLA Permissive v2.0 に基づいてるため、地図の作成やサービスに用いることができます。
今回の記事では、この画期的な地図データセットの公開に際して、実際にデータの中身を少し見てみます。無料のGoogle ColabでPythonを利用して、小さいデータで試験的に試します。
記事の目次
今回の記事のノートブックは、以下の「Open in Colab」ボタンをクリックすると開きます。
Google Colab の準備
まず以下の記事などを参考にGoogle Colabを使えるようにしておきます。
GPUは使わないので、ランタイムの種類を変更する必要はありません。
データセットの入手方法について
今回公開されたデータセット名は「Overture 2023-07-26-alpha.0」です。
データセットは「Parquet形式」のファイルで公開されており、「Amazon S3」と「Microsoft Azure」に配置されています。
Parquetファイルをそのままダウンロードもできますが、容量が大きいので、通常はSQLで問い合わせて必要なデータをダウンロードします。
AWSまたはAzureのアカウントがあれば Amazon Athena や Microsoft Synapse を使ってSQLを実行できますが、アカウントがなくても「DuckDB 」で問い合わせ可能です。
今回は、DuckDBを用いてAmazon S3にあるParquet形式の地図データセットにリモートアクセスして、SQLで必要なデータを入手します。
Placesデータセットを試してみる
Placesデータセットは、いわゆる「POI(Places of Interest)」と呼ばれる場所の位置データです。今回は東京駅の八重洲口付近のデータを入手して、どのようなデータが含まれているのか地図にプロットして確認してみます。
接続オブジェクトの作成
まずはDuckDB用の接続オブジェクトを作成します。Google Colabには、DuckDBのPython APIモジュール がプレインストールされているので、そのままimportして使えます。
import duckdb
con = duckdb.connect()
con.execute("INSTALL httpfs;")
con.execute("INSTALL spatial;")
con.execute("LOAD httpfs;")
con.execute("LOAD spatial;");
con.execute("SET s3_region='us-west-2';")
ここで、今回はDuckDBの拡張機能の「httpfs」と「spatial」が必要になるので、それぞれインストールして有効にしておきます。また、データの場所を探せるようにS3 regionも指定しておきます。
どんなカラムがあるか調べる
最初にカラムの一覧を調べるために以下のクエリを実行してみましょう。
query_places_desc = """DESCRIBE
SELECT *
FROM read_parquet('s3://overturemaps-us-west-2/release/2023-07-26-alpha.0/theme=places/type=*/*', filename=true, hive_partitioning=1);
"""
con.sql(query_places_desc)
実行すると以下のように18のカラムの内容が確認できます。
東京駅付近のPlacesデータを入手する
次に東京駅の八重洲口付近として139.768 < 経度 < 139.771
、35.680 < 緯度 < 35.683
の範囲に含まれるデータを以下のクエリで入手して「tokyo_places.geojson」ファイルに保存します。
query_tokyo_places = """COPY (
SELECT
JSON(names) AS names,
bbox.minx as minx,
bbox.maxx as maxx,
bbox.miny as miny,
bbox.maxy as maxy,
ST_GeomFromWkb(geometry) AS geometry
FROM read_parquet('s3://overturemaps-us-west-2/release/2023-07-26-alpha.0/theme=places/type=*/*', filename=true, hive_partitioning=1)
WHERE ST_GeometryType(ST_GeomFromWkb(geometry)) = 'POINT'
AND minx > 139.768
AND maxx < 139.771
AND miny > 35.680
AND maxy < 35.683
) TO 'tokyo_places.geojson'
WITH (FORMAT GDAL, DRIVER 'GeoJSON');
"""
con.sql(query_places_desc)
実行すると以下のように進捗が表示されます。
完了すると(当方では約4分かかりました)以下のように「tokyo_places.geojson」が保存されたのを確認できます。サイズは約140KBです。
これでデータの入手は完了したので、以下のコードで接続を閉じておきます。
con.close()
Placesデータを地図に表示してみる
次にfolium というPythonのモジュールを用いて、以下のコードでGeoJsonファイルを読み込みます。foliumを利用するとJupyter Notebookで地図データを簡単に視覚化できます。Google Colabにプレインストールされているので、すぐ使えます。
import folium
places = folium.GeoJson("/content/tokyo_places.geojson",
name="tokyo_places",
tooltip=folium.features.GeoJsonTooltip(fields=["names"]))
地図を表示する前に以下のコードでデータ数を確認します。今回のファイルには474地点のデータが含まれています。
len(places.data['features'])
では以下のコードを実行して地図に表示してみましょう。データを取得した中心の緯度経度をlocation=[35.6815,139.7695]
で指定します。
fmap = folium.Map(location=[35.6815,139.7695], zoom_start=17)
places.add_to(fmap)
folium.LayerControl().add_to(fmap)
fmap
実行すると以下のように入手したPlacesのデータを確認できます。マーカーにマウスをのせるとnames属性(場所の名前)が表示されます。
八重洲地下のお店などかなりの情報が公開されているのが分かります!
Administrative Boundariesデータセットを試してみる
同様にAdministrative Boundariesデータセット(Admins)も試してみます。方法はほぼ同じなので、おもにコードを掲載しておきます。
接続オブジェクトの作成
import duckdb
con = duckdb.connect()
con.execute("INSTALL httpfs;")
con.execute("INSTALL spatial;")
con.execute("LOAD httpfs;")
con.execute("LOAD spatial;")
con.execute("SET s3_region='us-west-2';")
どんなカラムがあるか調べる
今度はtheme=admins
になっているので、注意してください。
query_admins_desc = """DESCRIBE
SELECT *
FROM read_parquet('s3://overturemaps-us-west-2/release/2023-07-26-alpha.0/theme=admins/type=*/*', filename=true, hive_partitioning=1);
"""
con.sql(query_admins_desc)
日本のAdminsデータを入手する
Administrative Boundariesデータセットは、行政レベル(adminレベル)ごとの階層構造になっています。今回は「国レベル(adminLevel = 2
)」の日本の境界データを入手します。
query_japan_admins = """COPY (
SELECT
type,
subType,
localityType,
adminLevel,
isoCountryCodeAlpha2,
JSON(names) AS names,
JSON(sources) AS sources,
ST_GeomFromWkb(geometry) AS geometry
FROM read_parquet('s3://overturemaps-us-west-2/release/2023-07-26-alpha.0/theme=admins/type=*/*', filename=true, hive_partitioning=1)
WHERE adminLevel = 2
AND ST_GeometryType(ST_GeomFromWkb(geometry)) IN ('POLYGON','MULTIPOLYGON')
AND isoCountryCodeAlpha2 = 'JP'
) TO 'japan_admins.geojson'
WITH (FORMAT GDAL, DRIVER 'GeoJSON');
"""
con.sql(query_japan_admins)
完了すると「japan_admins.geojson」が保存されます。サイズは約190KBです。
con.close()
Adminsデータを地図に表示してみる
import folium
admins = folium.GeoJson("/content/japan_admins.geojson", name="japan_admins")
len(admins.data['features'])
日本の「adminレベル2(国レベル)」の境界データだけなので「1」になります。
fmap = folium.Map(location=[36.0,138.5], zoom_start=7)
admins.add_to(fmap)
folium.LayerControl().add_to(fmap)
fmap
位置情報の基本が学べる本
地図に関するプログラミングでは、位置情報に関する基本知識が不可欠です。以下の本では、位置情報の基本からアプリケーションの開発方法までわかりやすくまとまっています。