🗾

MapLibre GL JS と japanmesh で地域メッシュを表示する

2023/12/15に公開

はじめに

はじめまして、最近 MapLibre を使い始めた @qazsato です。

今まで Leaflet や Google Maps を使って地図サービスを作っていましたが、
ベクトルタイルの触り心地に感動し、現在 MapLibre に書き直しています。
カスタマイズ性も高く、あれこれ触っているうちに、気づけば地図の沼に浸かり始めてます🫠

今回は MapLibre GL JS 上に、地域メッシュを表示する方法をまとめます。

地域メッシュとは

地域メッシュとは、日本全土を緯度・経度に基づき地域を隙間なく網の目(メッシュ)に分けたものです。
このように日本をすっぽり覆います。
地域メッシュ 第 1 次地域区画
80km 地域メッシュ

また各メッシュには、 地域メッシュコード と呼ばれる 4 桁から 11 桁の一意な数字が割り振られており、桁数が大きくなるほど詳細なメッシュとなります。

大きさ毎に以下の8つに分類されます。

一辺の長さ 区画の種類 コード桁数 コード例
80km 第 1 次地域区画 4 桁 5339
10km 10 倍地域メッシュ (第 2 次地域区画) 6 桁 533945
5km 5 倍地域メッシュ 7 桁 5339452
2km 2 倍地域メッシュ 9 桁 (末尾 5 固定) 533945465
1km 基準地域メッシュ(第 3 次地域区画) 8 桁 53394529
500m 2 分の 1 地域メッシュ 9 桁 533945292
250m 4 分の 1 地域メッシュ 10 桁 5339452922
125m 8 分の 1 地域メッシュ 11 桁 53394529221

広域から狭域まで幅広くカバーされていますね。

今回はこの地域メッシュを簡単に扱える japanmesh[1] というライブラリを使って MapLibre 上に表示をしてみます。

https://www.npmjs.com/package/japanmesh

japanmesh の使い方

何はともあれインストール。

npm install japanmesh

1.緯度経度から地域メッシュコードに変換

一行です。

import { japanmesh } from 'japanmesh'

japanmesh.toCode(35.70078, 139.71475)

=> '53394547112'

2.地域メッシュコードからGeoJSONに変換

これまた一行。

import { japanmesh } from 'japanmesh'

japanmesh.toGeoJSON('53394547112')

=> {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [139.7156250, 35.7010416],
        [139.7140625, 35.7010416],
        [139.7140625, 35.6999999],
        [139.7156250, 35.6999999],
        [139.7156250, 35.7010416]
      ]
    ]
  }
}

今回は、この2つのメソッドを使います。
複数の緯度経度を、地域メッシュコードに変換 (japanmesh.toCode) し、さらにGeoJSON に変換(japanmesh.toGeoJSON)し、 MapLibre 上に表示してみます。

MapLibre GL JS への組み込み

まずは地図の生成です。

<div id="map"></div>
import { Map } from 'maplibre-gl'
import { japanmesh } from 'japanmesh'

type Coordinate = [number, number]
type MeshCount = { code: string; count: number }

const MESH_LEVEL = 2000 // 計測したいメッシュレベル。メートルで指定。

// 解析したい緯度経度の配列
const coordinates: Coordinate[] = [
  [139.681973, 35.713801],
  [139.429988, 35.561738],
  // ...
]

const map = new Map({
  container: 'map',
  style: 'https://tile.openstreetmap.jp/styles/osm-bright-ja/style.json',
  center: [139.767125, 35.681236],
  zoom: 10
})

次に、地図読み込み後の処理を追加します。
load 後、メッシュ毎に件数を集計して地図に描画します。

map.on('load', () => {
  const meshCounts = calcMeshCounts(coordinates, MESH_LEVEL)
  const maxCount = Math.max(...meshCounts.map(({ count }) => count))
  meshCounts.forEach(meshCount => createGeoJSONLayer(meshCount, maxCount))
})

// メッシュコード毎の件数を集計
function calcMeshCounts (coordinates: Coordinate[], level: number) {
  const count: Record<string, number> = {}
  coordinates.forEach(([lng, lat]) => {
    const code = japanmesh.toCode(lat, lng, level)
    count[code] = count[code] ? count[code] + 1 : 1
  })
  return Object.entries(count).map(([code, count]) => ({ code, count }))
}

// メッシュコード毎の GeoJSON を作成
function createGeoJSONLayer (meshCount: MeshCount, maxCount: number) {
  map.addSource(meshCount.code, {
    type: 'geojson',
    data: japanmesh.toGeoJSON(meshCount.code)
  })
  map.addLayer({
    id: meshCount.code,
    type: 'fill',
    source: meshCount.code,
    paint: {
      'fill-color': '#00B0FF',
      'fill-opacity': meshCount.count / maxCount
    }
  })
}

東京23区の銭湯 (2km メッシュ)
東京23区の銭湯 (2km 地域メッシュ)

出力例です。
東京23区の銭湯の緯度経度を、 2km 地域メッシュで表示してみました。
色が濃いほど銭湯が密集しています。
台東区には銭湯がまだまだ多く残っていそうですね。

おわりに

以上、MapLibre と japanmesh による地域メッシュの可視化でした。
50行程度のコードで、メッシュによる可視化が作成できるのはお手軽ではないでしょうか。

また、地域メッシュコードは国が定めたコード体系であるため、地域メッシュに基づいた統計データ[2]も数多く提供されています。

ぜひ、様々なデータを japanmesh で可視化してみてください。

蛇足

今回取り上げなかったですが、 MapLibre はベクトルタイルなので 3D 表示も可能です。
そのため、テレビでよく見かける 3D 降水量マップも作れます。
MapLibre の fill-extrusion レイヤーを使うことになると思います。

https://maplibre.org/maplibre-gl-js/docs/examples/3d-buildings/

また、気象庁はデータ[3]だけでなく、カラーコード[4]も公開しています。
3D グラフに興味のある方は、この記事の応用編として試してみてはいかがでしょうか。
結果を共有していただければ幸いです😊

脚注
  1. https://github.com/qazsato/japanmesh ↩︎

  2. https://www.e-stat.go.jp/gis/statmap-search?type=1 ↩︎

  3. https://www.data.jma.go.jp/stats/data/mdrr/docs/csv_dl_readme.html ↩︎

  4. https://www.jma.go.jp/jma/kishou/info/colorguide/HPColorGuide_202007.pdf ↩︎

Discussion