町丁目ポリゴンのPMTilesサーバーを立てて、Leafmapでタイル表示してみる

## はじめに
[Leafmap](https://leafmap.org/)（プロットバックエンドは folium）でも[PMTiles](https://docs.protomaps.com/pmtiles/)形式のベクトルタイルを表示できるらしいので、実際に試してみることにしました。
Leafmapについてですが、初めて扱った時の記事が以下になります。よろしかったらご参照下さい。

https://qiita.com/y-mto/items/321c113eb5a161cd46dc

## 町丁目ポリゴンのベクトルタイル
[TerraMap API](https://www.mapmarketing.co.jp/terramap-api?grid=qiita&utm_source=qiita.com&utm_medium=referral&utm_campaign=qiita_pmtiles_on_leafmap_19ef50c66e2a5949921f_01)でも提供している町丁目ポリゴンデータを利用しました。[tippecanoe](https://github.com/felt/tippecanoe)でGeoJSONファイル等をベクトルタイルに変換する必要がありますが、今回は単一ファイルであるPMTiles形式を選びました。

変換作業に関しては以下記事をご参照下さい。地図表示させたいポリゴンのGeoJSONファイルをお持ちでしたら、同じようなことができると思います。

https://qiita.com/y-mto/items/f7614c3e3e5d11a59bbe

## NginxによるPMTilesサーバー
NginxのDockerイメージを使ってPMTilesファイルを提供させます。ファイル構成は以下のようにしました。

```none:ファイル構成
root/
 ├── nginx.conf
 ├── Dockerfile
 └── pmtiles
      └── chomoku.pmtiles
```

### Nginxの設定ファイル
CORSを有効にするため、設定を変更しています。
```properties:nginx.conf
server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        autoindex off;  # ファイルリストの有無（必要に応じて）

        # CORSヘッダーの設定    ※ 本番ではオリジンを適切に設定します
        add_header Access-Control-Allow-Origin * always;
    }
}
```
### Dockerfile
```dockerfile:Dockerfile
FROM nginx:latest

ADD ./nginx.conf /etc/nginx/conf.d/default.conf
ADD ./pmtiles /usr/share/nginx/html

RUN echo "start nginx"
```
### ビルドおよびコンテナ実行
```
docker build -t pmtiles-server .
docker run --name pmtiles-server -d -p 8080:80 pmtiles-server
```

## 地図アプリ作成
Leafmapを利用した地図アプリに関しては、Pythonでコーディングします。
### 環境準備
Pythonやpipを使えるようにして、まずはleafmap、geopandas、streamlitをインストールします。
```:パッケージのインストール
pip install leafmap geopandas streamlit
```
### Pythonコード
```python:app.py
import leafmap.foliumap as leafmap

url = "http://localhost:8080/chomoku.pmtiles"

style = {
    "version": 8,
    "sources": {
        "mvt_data": {
            "type": "vector",
            "url": "pmtiles://" + url,
            "attribution": "PMTiles",
        }
    },
    "layers": [
        {
            "id": "mvt_polygon",
            "source": "mvt_data",
            "source-layer": "chomoku-layer",    # PMTilesのレイヤー名
            "type": "fill",
            "paint": {"fill-color": "#7fffd4", "fill-opacity": 0.2},
        },
        {
            "id": "mvt_line",
            "source": "mvt_data",
            "source-layer": "chomoku-layer",    # PMTilesのレイヤー名
            "type": "line",
            "paint": {"line-color": "#2e8b57", "line-width": 0.5},
        },
    ],
}

def main():
    # Mapオブジェクト作成
    m = leafmap.Map(
        # コントロールは最小限に
        draw_control=False,
        measure_control=False,
        # 中心位置とズームレベル指定
        center=(35.71967, 139.65313), zoom=9,
    )

    # PMTilesを表示
    m.add_pmtiles(
      url, name="chomoku", style=style, overlay=True, show=True, zoom_to_layer=False, tooltip=False
    )

    # 地図をStreamlitアプリ内に描画
    m.to_streamlit(height=500)

if __name__ == "__main__":
    main()
```
`style` に関しては、ベクトルタイルのソースやレイヤーの細かい設定を書く必要がありますが、他の部分は比較的短いコードで済みました。

参考情報

https://leafmap.org/notebooks/82_pmtiles/

## 動作確認
```:アプリの起動
streamlit run app.py
```

アプリを起動すると、以下のような地図表示になりました。

![pmtiles_polygons.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2893989/88957988-26f6-4652-a0dc-450ffead0f63.gif)