地理院地図の人口メッシュデータを軽量化

## はじめに

先日、地理院地図へ全国の人口情報が掲載されはじめました。

https://www.gsi.go.jp/johofukyu/johofukyu60001_00015.html

データの出典は、令和2年国勢調査に関する地域メッシュ統計（総務省）の人口データのようです。報道発表では「防災・災害対応への活用などが期待される」とあります。

実は、先の能登半島地震に関連して地理院地図から公開されたデータにも能登半島部分における同様の人口メッシュデータが含まれていました。

https://www.gsi.go.jp/BOUSAI/20240101_noto_earthquake.html#11

救助や支援を行う場合、どの地域にどのくらいの人が住んでいるのかは重要な情報と考えられます。今回の全国データの公開は、先の地震を踏まえ、人口メッシュデータの有用性が認識された結果なのかもしれません。

今回は、このデータを利用して、人口メッシュデータをより軽快に表示する方法を検討してみたいと思います。

## 改善点の検討

今回のデータを閲覧してみて感じた改善点は以下の通りです。

* データサイズが大きい
* もう少し小さいズームレベル（ZL）から表示したい

### データサイズが大きい

今回の人口メッシュデータは GeoJSON タイルデータで提供されています。提供範囲は ZL12～18 までですが、実態としてはタイルデータは ZL12～15 まで存在し、そこから先はオーバーズーミングで表示しているようです。

GeoJSON の場合、オーバーズーミングでも座標値が悪化しないことと、調べてみた限り、１ファイル当たり最大 300 kb 程度なので、ZL12 だけ準備してあとはオーバーズーミングでも良いのかもしれません。そうすれば、ZL を変更した際に新たにデータを読み取る必要はありません。（ただし、直接大縮尺で閲覧することを考えると、ZL15 まで準備する意味はあります。）

データの中身としては、地理院地図のスタイル設定ファイル（[ベクトルタイルスタイル定義 style.js 規約](https://github.com/gsi-cyberjapan/style-dot-js-spec)）を利用するのではなく、各メッシュデータに直接スタイル情報（[スタイルつき GeoJSON 規約](https://github.com/gsi-cyberjapan/geojson-with-style-spec)）が記載されています。これは重複が大きく、データ削減の余地があると思われます。

### もう少し小さいズームレベルから表示したい

紙の地図では、１つの都道府県を俯瞰できるような縮尺の地図（20万分の１地勢図）には、市街地が表示されていますが、現在の地理院タイル（標準地図・淡色地図）にはそのようなデータはありません。人口メッシュデータは、市街地データに相当するデータ（災害時等においてはむしろ直接必要となるデータ）として期待できます。

一方、[先に記事にした](https://qiita.com/mg_kudo/items/2addfe3bc7d8ab252b25)ように、能登半島をカバーするような縮尺は ZL10 となり、今回の提供範囲（ZL12～18）では、１つの都道府県を俯瞰するような利用には物足りなくなる場合もあります。

当然、小縮尺からこのようなメッシュデータを表示させると、データ量がますます大きくなりますから、工夫が必要となります。

## 対応策

今回必要な対応としては、「小縮尺から表示しても動作に問題ないようにデータを軽量化する」ということです。具体的には以下の対策を行いました。

* GeoJSON から Mapbox Vector Tile 形式へ変換する。
* ポリゴンではなく、ポイントデータ（メッシュの中央点）へ変換する。
* スタイル関係の情報は捨てる（ウェブサイト側で人口データからスタイルを再現する）。
* 小縮尺はクラスタリングを用いて地物数を削減する。

小縮尺においては、１メッシュごとの正確な色分けよりも、どの地域に人が集まっているかの概観をつかむことが重要と考えたので、ヒートマップを採用することとしました。クラスタリングを用いると見た目が悪化するため、それをケアするためでもあります。

## データ変換

具体的な方法としては、[mokuroku](https://github.com/gsi-cyberjapan/mokuroku-spec) を頼りに、ZL12 の人口メッシュデータを地理院地図サーバから取得しました。これをポイントデータへ変換し、[tippecanoe](https://github.com/felt/tippecanoe) で Mapbox Vector Tile 形式へ変換しました。この記事執筆時点では、ZL10 に全メッシュに相当するポイントデータを格納する完全なデータとして、ZL9～6 は tippecanoe の機能でクラスタリングを行いました。

## 結果の表示

表示については、MapLibre GL JS を用いています。ZL6~14 はヒートマップを表示し、ZL12 からメッシュ毎のポイントデータを表示しはじめ、ZL14 からはヒートマップの代わりに各メッシュの人口の数字を表示しています。

## デモサイト

https://mghs15.github.io/population-mesh-via-gsimaps/

※色合いは地理院地図のものを参考にしていますが、厳密に数字が合っているわけではありません。

:::note alert
実は、地理院地図の GeoJSON ベクトルタイルは、タイル境界で１つのメッシュが分割されています。これをそのまま区別せずに変換したため、**ZL12のタイル境界付近のデータは重複して含まれる**ことになります。特にヒートマップではその部分の重みづけが実態よりも過剰になるため、閲覧時には注意してください。
:::

レポジトリはこちら

https://github.com/mghs15/population-mesh-via-gsimaps

## 各種表現の比較

地理院地図ではメッシュデータをメッシュのポリゴンそのままで表示していましたが、今回はポイントデータへの変換を行いました。表現について、ポリゴンとポイント、それからヒートマップを比較してみます。（ポイントとヒートマップはタイル境界のデータに重複があることに注意ください。）

ポリゴン（地理院地図）
![ポリゴンでの表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/3e22752e-764f-6b24-6a69-54cbec6e0683.png)

ポイント
![ポイントでの表示.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/1a9bbb80-9c85-7353-a081-9808df2cbe3e.png)

ヒートマップ
![ヒートマップでの表示.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2842832/74eab2dd-3f7d-9cf8-09f3-e46f1816f098.jpeg)

## よりよい方法

国勢調査のデータは、250 m メッシュだけでなく、500 m メッシュ、1 km メッシュのデータも提供されています。

https://www.e-stat.go.jp/gis/statmap-search?page=1&type=1&toukeiCode=00200521

これらを集計することで、さらに粗いメッシュのデータも生成できます。今回のような機械的なクラスタリングに頼るよりも、ZL10 は 250 m メッシュデータ、ZL9 は 500 m メッシュデータ、ZL8 は 1 km メッシュデータ……と階層的に表示した方が理想的でしょう。

また、今回は地理院地図のデータを流用したため、タイル境界のデータ重複の課題にぶつかり、結局対応を放棄しました。この点からも元データを利用する方がベストです。

:::note warn
ただ、元データを全国分一括取得する方法が見つからず、今回は見送りました……。
:::

また、令和６年能登半島地震では、能登半島の地形に加え、高齢化率の高さも課題になりました。統計データでは、人口だけでなく、様々な特性のデータも提供されていますので、高齢化率等も含めたよりリッチな地図も作成できるかと思います。

## 感想

地理院地図で人口データを簡便に閲覧できるようになりました。これに刺激を受けて、より自分が使いやすいデータ提供の形を検討してみました。

今回はタイル境界の処理を放棄する中途半端な結果でしたが、それでも全国の傾向はなんとなくつかめると思います。

また、個人的には、ZL9～11 というのは便利な縮尺だと考えておりますので、またいろいろと材料を探して検討したいです。