パントレ開発部

GeoJSON から PMTiles を生成する方法(WSL/Ubuntu)

Programming

 世界地図の PMTiles を生成する方法です。GeoJSON に限らないかもです。マップタイルそのものに関する解説は以下にあります。

はじめに

PMTiles とは

 PMTiles とは、タイル化されたデータ(ラスタ/ベクトル含む)をサーバレス/単一ファイルで配信できるファイル形式です。従来のマップタイルと遜色なく、高速に動作します。MapLibre 等を用いて、ブラウザ上で表示することが可能です。

 PMTiles を生成する方法は幾つかあるのですが、今回は Windows で仮想 Linux 環境をつくり、felt/tippecanoe を用いて PMTiles を生成する方法について説明します。(Docker 環境で行う方法もあるのですが、作成した PMTiles を MapLibre で表示させようとすると、なぜかたまに “Wrong magic number for PMTiles archive” のエラーを吐いて、表示できなくなります。GeoJSON → MBTiles → PMTiles と手順を踏んでも同じような症状になります。謎です。)

felt/tippecanoe とは

 tippecanoe(ティピカノー)は Mapbox がメンテナンスしていたオープンソースソフトウェアです。2021 年以降コードに変更がなかったのですが、2022年に tippecanoe が felt という地図サービスを提供する組織にフォークされ、Mapbox社でtippecanoeを開発していたエンジニアが felt へジョイン、活発な開発が再スタートしました。今後は felt/tippecanoe を使っていくのがよさそうです。

 以下 GeoJSON の準備 → felt/tippecanoe を使った PMTiles への変換 → MapLibre での表示 の順で説明していきます。

GeoJSON の準備

 今回は、shape ファイルをダウンロードし、QGIS で shape ファイルを GeoJSON に変換することで、GeoJSON を準備したいと思います。

shape ファイルのダウンロード

 ここで、shape ファイルは Natural Earth というサイトからダウンロードします。「Downloads」→「Large scale data, 1:10m」→「Cultural」→「Admin 0 – Countries point-of-views」→「Download countries (Japan POV) 」と進むと、日本基準の詳細な国境線データ(shape ファイル)がダウンロードできます。

▲ Natural Earth のサイト

GeoJSON への変換

 ダウンロードしたファイルを GeoJSON に変換します。zip ファイルを解凍し、中の shape ファイル(拡張子.shp)を QGIS で開きます。QGIS のダウンロードはこちらからできます。QGIS の画面に shape ファイルをドラッグ&ドロップすると、レイヤが追加されるので、追加されたレイヤを右クリック → 「エクスポート」→「新規ファイルに地物を保存」を選択します。

▲ QGIS の画面

 形式を「GeoJSON」、CRS を「ESPG:4326 – WGS 84」とし、ファイル名を入力、「OK」をクリックすれば、GeoJSON が保存されます。ここでは、ファイル名を「countries_boundaries」としました。

 以上で GeoJSON の準備は終了です。

PMTiles への変換

 PMTiles の変換には前述のように felt/tippecanoe を使うのですが、Windows 上で直接実行することはできないので、仮想 Linux (WSL/Ubuntu) 環境を整えたうえで、felt/tippecanoe をダウンロード、実行していきます。

WSL (Ubuntu) のダウンロード

 Windows Powershell もしくはコマンドプロンプトを管理者権限で開き、以下のコマンドを入力して WSL をインストールします(参考)。

wsl --install

 インストールが終わると、再起動を要求されるので、いったん再起動します。その後、Windows Powershell を開くと、新しいタブを追加する欄に Ubuntu が追加されているはずなので、そちらを開きます。初めて使う場合、UNIX user アカウントの作成が要求されます。「Enter new UNIX username:」と表示されるので、適当なユーザー名を入力、次に「New password:」と表示されるので、任意のパスワードを入力します。

felt/tippecanoe のダウンロード

 Windows Powershell で Ubuntu を開き、 以下のコマンドを順に実行していきます。

sudo apt-get install software-properties-common
sudo apt-add-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git
sudo apt-get install unzip
sudo apt-get install wget
git clone https://github.com/felt/tippecanoe.git
cd tippecanoe
sudo apt install make
sudo apt-get install build-essential libsqlite3-dev zlib1g-dev
sudo make install

 詳細はこちらを参照してください。ここで、Mapbox の tippecanoe ではなく、felt の tippecanoe をダウンロードするため、「git clone https://github.com/felt/tippecanoe.git」となっている点をご注意ください(僕は一回間違えて Mapbox のものをダウンロードしてしまいました)。以下のコマンドを入力して、バージョンが表示されれば、felt/tippecanoe はダウンロードできています。

tippecanoe --version

GeoJSON → PMTiles

 先ほど準備した GeoJSON を、適当なフォルダに移します。ここではわかりやすいように C ドライブのユーザーフォルダとします。エクスプローラーに「\\wsl$」と入力すると、WSL のフォルダに入れるので、Ubuntu/home/UNIX ユーザー名 のフォルダ上で作業してもよいかもしれません。
 Windows Powershell で Ubuntu を開き、GeoJSON があるフォルダに移動します(ここではCドライブのユーザーフォルダ)。

cd /mnt/c/Users/ユーザー名

 Ubuntu で以下のコマンドを実行して、GeoJSON を PMTiles に変換します。

tippecanoe -o countries_boundaries.pmtiles -Z0 -z5 -pf -pk -l countries_boundaries countries_boundaries.geojson
  • -Z:最小ズームレベル。
  • -z:最大ズームレベル。(11ぐらいが標準的なPCで処理できる限界だと思います。ズームレベルを1あげると、単純に処理時間は4倍ぐらいになります。)
  • -pf:地物数制限を無視する。
  • -pk:ファイルサイズ制限を無視する。
  • -l:単一レイヤーにまとめる。

 この場合は、ズームレベル 0-5 で、ファイル制限せず、countries_boundaries という名前の単一レイヤにまとめて、GeoJSON を PMTiles に変換するコマンドとなります。
 GeoJSON と 同じ階層に PMTiles が出力されるので、PMTiles Viewer でうまく生成されているかを確認します。 この条件で生成されたファイルは 4 MB ぐらいでした。(ちなみに、ズームレベル 0-11 だと、320MB ぐらいになりました。)

MapLibre で表示する

 MapLibre で PMTiles を表示するには、MapLibre の他に PMTiles パッケージを読み込む必要があります。

<link rel='stylesheet' href='https://unpkg.com/maplibre-gl/dist/maplibre-gl.css' />
<script src='https://unpkg.com/maplibre-gl/dist/maplibre-gl.js'></script>
<script src="https://unpkg.com/pmtiles/dist/pmtiles.js"></script>

 地図を表示するための div 要素を HTML 上で作ります。

<div id='mapcontainer' style='width:100%; height:300px; z-index:0;'></div>

 以下のようなコードでブラウザ表示できるようになります。

jQuery(document).ready(function(){
    const protocol = new pmtiles.Protocol();
    maplibregl.addProtocol('pmtiles', protocol.tile);
    const PMTILES_URL = 'PMTiles の URL';
    const map =  new maplibregl.Map({
        container: 'mapcontainer',
        style: {
            version: 8,
            glyphs: 'https://demotiles.maplibre.org/font/{fontstack}/{range}.pbf',
            sources: {
                'countries_boundaries': {
                    type: 'vector',
                    url: `pmtiles://${PMTILES_URL}`
                }},
            layers: [
                {
                    id: 'background',
                    type: 'background',
                    paint: { 'background-color': '#dddddd' }
                },
                {
                    'id': 'countries_boundaries',
                    'type': 'fill',
                    'source': 'countries_boundaries',
                    'source-layer': 'countries_boundaries',
                    'paint': {
                        'fill-color': '#84C98B',
                    },
                },
                {
                    'id': 'countries_boundaries_border',
                    'type': 'line',
                    'source': 'countries_boundaries',
                    'source-layer': 'countries_boundaries',
                    'paint': {
                        'line-color': '#2B6442',
                        'line-width': 1,
                    },
                }
            ]
        },
        center: [136, 38], 
        zoom: 0.5,
        minZoom: 0,
        maxZoom: 5,
        pitch: 0
    });
});

 実装例

 

少し宣伝

 当サイトは、以上のような手順で生成した PMTiles を積極的に使った、海外旅ブログまとめサイトとなっています。トップページに地図(PMTiles!)がありますが、地名を押すと画像が開き、画像を押すと関連記事一覧(クリック数順)が開きます。地名もその国で記事が多い都市の文字が大きくなるようにしています。ぜひ覗いてみてください。
 当サイトで海外旅ブログを執筆することも可能です(もちろん無料です)! また既にブログをお持ちの方も、当サイトからリンクを貼ることができるようになっています。パントレ開発部までお気軽にお問い合わせください。

パントレ開発部