bb.xrea.jp

2024-12-12 作成 / 2025-05-31 更新

GISファイル軽量化の備忘録

ペイントマップ」では、国土数値情報の行政区域データを使用して地図を描画している。元のGeoJSONファイルは500MB近くある一方、当アプリではそこまで正確な地図は必要ないため、ポリゴンの簡素化によってファイルサイズを削減している。地図の追加や市町村合併等の対応時に同様の作業が必要になるので、自分用の備忘録として作業手順を残しておく。

※以下、「全国:2024年(令和6年)」の「N03-20240101.geojson」を使用した場合のファイル容量を参考として記載している。

1. 行政区域データを準備

国土交通省の国土数値情報ダウンロードサイトより、行政区域データをダウンロード。 都道府県ごとのデータを個別に処理すると、簡素化後のデータを一枚の地図にまとめたときに都道府県境界がずれることがあるので、常に全国版のデータを使用する。同様の理由で、ダウンロードサイト内に用意された都道府県の区域データは使わず、市区町村別のデータのジオメトリを融合して生成する。

代替テキスト https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html

2. ポリゴンを簡素化

mapshaperを使用して、ポリゴンの簡素化およびTopoJSONへの変換を行う。QGISでは動作が重すぎて扱いずらいファイルも処理できたり、TopoJSONに変換することで簡素化しても市町村の間に隙間ができないようにできる。

簡素化の程度はファイル容量と精度の兼ね合いで決まるが、本アプリの用途では0.50%程度まで簡素化しても問題なさそう。geoJSON形式でエクスポートする。 (475 MB → 22.5 MB)

代替テキスト

3. ジオメトリのエラー修正

QGISでgeoJSONファイルを読み込み、メニューバーの「プロセシング」→「ツールボックス」→「ベクタジオメトリ」→「ジオメトリの修復」を実施。エラーが残っていると次のステップが落ちるのでこのタイミングで実行。

代替テキスト

4. ジオメトリの融合

一つの市町村が複数のFeatureから構成されており、propertiesの記載が重複して容量を食っているので、1つの市区町村ごとに1つのFeatureにまとめて容量を削減する。

圧縮前のデータ構造

{"type":"FeatureCollection", "features": [
  ...,
  {"type":"Feature","geometry":null,"properties":{"N03_001":"北海道","N03_002":"渡島総合振興局","N03_003":null,"N03_004":"函館市","N03_005":null,"N03_007":"01202"}},
  {"type":"Feature","geometry":null,"properties":{"N03_001":"北海道","N03_002":"渡島総合振興局","N03_003":null,"N03_004":"函館市","N03_005":null,"N03_007":"01202"}},
  {"type":"Feature","geometry":null,"properties":{"N03_001":"北海道","N03_002":"渡島総合振興局","N03_003":null,"N03_004":"函館市","N03_005":null,"N03_007":"01202"}},
  {"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[140.84480981,43.2003834],...]]},
  ...
}

QGISのメニューバーの「ベクタ」→「空間演算ツール」→「融合 (dissolve)…」を実施。

代替テキスト

| 作成する地図 | 「基準とする属性」設定 | | ---- | ---- | | 市区町村境界データ | すべて | | 政令市の区をまとめたデータ | N03_001, N03_002, N03_003, N03_004 | | 都道府県境界 | N03_001 のみ |

市区町村境界データについては、22.5 MB → 4.5 MBまで圧縮できる。

5. 改行・スペースの削除

QGISがエクスポートするJSONは改行・スペースを含むので、これらを削除。JSON.parse()JSON.stringify() を連続で実行するのが早い。(4.5 MB → 3.7 MB)

6. gzip圧縮

.htaccessにてgzip圧縮の設定を行う。(3.7 MB → 1.0 MB)

SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSI[E] !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|ico)$ no-gzip dont-vary
Header append Vary User-Agent env=!dont-vary

7. 微調整

ペイントマップでは、properties.N03_004 (市町村名) が"所属未定地"であるようなFeatureは不要なので削除する。合わせて、必要に応じてpropertiesの形式を変更したり、Featuresの並び順を市町村コード順にしておく。

下記はJavaScriptで市区町村単位のデータを処理するプログラム例。市町村単位の場合、政令市の自治体コードの修正が必要。(行政区のコードになっているため)

delete data.name;
delete data.crs;
data.features = data.features.filter(feature=>feature.properties.N03_004 !== "所属未定地").map(({geometry, properties, type}) => ({
    geometry,
    properties: {
        code: properties.N03_007,
        name: properties.N03_005 ?? properties.N03_004,
        fullname: properties.N03_005
            ? properties.N03_004 + properties.N03_005
            : properties.N03_003
            ? properties.N03_001 + properties.N03_003 + properties.N03_004
            :  properties.N03_001 + properties.N03_004
    },
    type
})).sort((a,b) => a.properties.code - b.properties.code);

8. 確認

適切にデータが処理できていれば、区域数とfeaturesの要素数が一致しているはず。(一致していない場合、propertiesのデータが重複していて容量を食ったり、飛地部分だけ塗られない問題が生じる可能性がある。)

市区町村単位のデータの場合は1898件になるはず。(市町村1718 + 北方領土6 + 東京特別区23 - 政令市20 + 政令市の区171) 市町村単位のデータの場合はは1747件になるはず。(市町村1718 + 北方領土6 + 東京特別区23)

9. まとめ

GISファイルの容量削減手順をまとめた。 ただし、現状でも画面表示までに4〜5秒程度かかる場合があるので、サーバの速度等も含めて改善を検討したい。

2025-05-31追記

webアプリからJSONを読み込む際に { cache: "force-cache" } オプションを追加したところ、キャッシュが有効活用でき読み込み速度が向上した。もう少し大容量のジオメトリデータを扱える余地はありそう。

その他の記事