4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Jupyter × 地図の決定版!Lonboardでらくらく100万ポイント描画!

Last updated at Posted at 2025-12-02

image.png

これは DuckDB Advent Calendar 2025 の3日目の記事です。

データの解析をやる場合、普通Python(Jupyter)などで解析しながらグラフや図などを可視化しつつ分析すると思います!

地理(GIS)データを取り扱っている場合は、当然地図上に可視化しながら分析を行うわけですが、その他のデータに比べてさほどハードルは高くなく、Leafmapのようなツールを利用すると簡単に可視化することができます!

ただ、Leafmapに限らず、GeoPandasのplot()やFoliumなど、
Matplotlib/Leaflet ベースのライブラリは、数千〜数万ポイントを超えるあたりから「ブラウザやノートブック側が重くて実用にならない」という共通の悩みがあります。

当然、数十万という地物数を想定して設計されていないので当然のことではあるんですが、例えば東京都の建物は100万件を超えると言いますし、100万件程度のデータを可視化することは、近年ではままあります。

こういった悩みを解決してくれるのがLonboardです。

Deck.glという大規模データセットの可視化に特化したWebGLベースの地図フレームワークを、Pythonから扱えるようにしたライブラリで、大量のデータを高速に描画することができます。

加えて、ファイルやメモリ上のデータに対して、SQLで分析可能なデータベースエンジンであるDuckDBは、大量の表形式データ(CSV、Parquet、Arrowなど)をSQLで超高速に処理できます。

これらを組み合わせて利用することで、大規模データセットを高速に処理し、さらに可視化まで行うことができます!

便利ですねー!

早速使っていきましょう!

データの準備

uvによる環境構築・ライブラリのインストール

データ分析にはPythonを利用することがとても多いです。
LonboardもPythonで利用可能なので今回はPythonを利用して分析と可視化を行なっていきます。
昔は色々なツールが乱立していたのですが、現代ではuvを利用するのが吉です。以下のような特徴があります。

  • 速度が非常に速い
  • インストールが簡単
  • 仮想環境や依存関係、Pythonのバージョンなどを自動管理

基本的には公式サイトを参照して環境構築すべきですが、macOSでインストールし、必要なパッケージもインストールする方法だけ載せておきます!

uvのインストール

❯ curl -LsSf https://astral.sh/uv/install.sh | sh
...
everything's installed!

❯ uv --version
uv 0.9.5 (d5f39331a 2025-10-21)
...

プロジェクトの作成とPythonの固定

mkdir demo-project && cd demo-project
❯ uv python install 3.13
❯ uv python pin 3.13
❯ uv init
❯ uv run python -V
❯ uv add duckdb jupyterlab lonboard
❯ uv sync

これでとりあえずPythonなどを起動させるため環境が整いました!

データのダウンロード

まずはデータを用意します!
今回はOverture Mapsを使います。
Overture Mapsは、AWS・Metaなどの複数企業・団体が連携して提供するオープンな地理空間データ基盤です。建物や道路、POI(お店・施設)などのデータが無料で手に入るのが最大の魅力です。
形式はGeoParquetなどで取得できます。

本記事ではPOI(places)をサンプルとして扱います。

Overture Maps CLIの使い方

CLIで地域やテーマを指定してダウンロードできます。

前提としてoverturemapsパッケージを入れておく必要があります(CLI overturemaps が使えるようになります)。

  • パッケージの追加
❯ uv add overturemaps
❯ uv sync

東京23区のデータをダウンロード

まずは東京23区を包括するようなエリアを指定してplaceを取得します。

mkdir data

❯ uv run overturemaps download \
    --bbox "139.0,35.1,140.3,36.2" \
    -f geoparquet \
    -t place \
    -o data/tokyo_places.parquet

このデータを、DucKDBで利用します。

※20251202現在では、overturemaps-pyが2025-09-24.0以前の古いリソースしか選択できないようになっているのに、S3からデータ消えていてダウンロードできないバグがあります。

このため、パッケージがインストールされている.venv内の、.venv/lib/python3.13/site-packages/overturemaps/core.pyを直接修正して実行しました。

...

# Keep the latest release at the bottom!
ALL_RELEASES = [
    '2025-08-20.0',
    '2025-08-20.1',
    '2025-09-24.0',
    '2025-10-22.0', # 追加!
    '2025-11-19.0', # 追加!
]

...

DuckDBとは

DuckDBはファイルやメモリ上のデータに対して、SQLで分析可能なデータベースエンジンです。大量の表形式データ(CSV、Parquet、Arrowなど)をSQLで超高速に処理できます。
地理空間情報向けの拡張機能もあり、GeoPandasが「Pythonで、データ分析しながら少しずつ触る」のに向く一方、DuckDBは「SQLで宣言的に一気に処理」するのが得意です。最初はGeoPandasで把握し、重くなったらDuckDBに寄せる、という使い分けも良いかもしれません。

インストール・初期設定

DuckDBはCLIとしても利用できますが、Pythonのライブラリも整備されています。インストールなどはuvで簡単に行えます。
今回はすでに行なっているので、さっそくコードを書いていきましょう。

# 必要なライブラリをインポート
import duckdb
from pathlib import Path
from lonboard import Map, ScatterplotLayer, PolygonLayer, PathLayer

# DuckDB接続を作成(メモリ内データベース)
conn = duckdb.connect()
print(f"DuckDBバージョン: {conn.execute('SELECT version()').fetchone()[0]}") # DuckDBバージョン: v1.4.1

# Spatial拡張をインストール(初回のみ)
conn.execute("INSTALL spatial")

# Spatial拡張をロード
conn.execute("LOAD spatial")

基本的なクエリ

空間拡張のspatialを導入すると、WKT/WKB/GeoJSONの相互変換、距離・バッファ・交差判定などが使えます。初回はINSTALL spatial;、以降はLOAD spatial;で有効化が必要です。
spatial extensionの基本的な関数はこちらに書いています。

ほんの少しだけ触ってみましょう。

# GeoParquetファイルのパスを確認
places_path = "data/tokyo_places.parquet"
print(f"Places: {Path(places_path).stat().st_size / 1024**2:.1f} MB")
# Places: 125.5 MB


# 基本的なクエリ: レコード数を確認
query = f"""
    SELECT COUNT(*) as count
    FROM '{buildings_path}'
"""

# 基本的なクエリ: レコード数を確認
query = f"""
    SELECT COUNT(*) as count
    FROM '{places_path}'
"""

result = conn.execute(query).df()
print(f"POIレコード数: {result['count'][0]:,}")
#POIレコード数: 829,816

# 指定範囲の地物を抽出
query = f"""
    SELECT COUNT(*) as count
    FROM '{places_path}'
    WHERE ST_Within(
        geometry,
        ST_MakeEnvelope(139.74,35.67,139.78,35.70)
    );
"""

result = conn.execute(query).df()
print(result)
#    count
# 0  36581

# 指定箇所から最寄りの地物を検索
query = """
    SELECT
        names.primary AS name,
        ST_Distance(geometry, ST_Point(139.745427, 35.658667)) AS dist_raw
    FROM read_parquet('data/tokyo_places.parquet')
    ORDER BY dist_raw
    LIMIT 1;
"""

result = conn.execute(query).df()
print(result)
#              name  dist_raw
# 0  Siddique Palace  0.000035

100万レコードには微妙に足りなかったんですが、許してください。
見ての通り、.df()メソッドなどが用意されており、Pandasと即時連携可能です。

DuckDBとLonboardの連携

LonboardはPythonにおけるGISエコシステムと密接に関係しており、前項で説明したようなGeoPandasだけでなく、DuckDBともスムーズに連携可能です。

# POI(ポイント)
sql_p = """
    SELECT geometry
    FROM read_parquet('data/tokyo_places.parquet')
"""
rel_p = conn.sql(sql_p)
layer_p = ScatterplotLayer.from_duckdb(
    rel_p,
    # 色設定
    get_fill_color=[0, 255, 100, 220],  # 緑
    get_line_color=[255, 255, 255, 100],  # 白枠
    # サイズ設定
    get_radius=30,
    radius_units="meters",
    radius_min_pixels=2,
    radius_max_pixels=10,
    # スタイル
    stroked=True,
    filled=True,
    line_width_min_pixels=0.5,
    pickable=True,  # マウスオーバー機能
    crs="EPSG:4326",
)

# マップ作成
m = Map(
    layers=[layer_p],
    view_state={
        "longitude": 139.75,
        "latitude": 35.68,
        "zoom": 12,
        "pitch": 0,
        "bearing": 0,
    },
)
m

image.png

ギチギチに詰まっており見づらいですが、大量のポイントが可視化できてるのがわかりますね!

おわりに

今回はざっくり以下のようなことをやっていきました。

  • Overture Mapsの取得
  • Lonboardでの大量データ可視化
  • DuckDBデータをLonboardで直接可視化

DuckDBでは分析は容易にできますし、Lonboardの可視化もスムーズにいきます!

これで、大規模な基本的な地理空間情報分析ができるようになりました!
みなさんもやってみてください!

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?