オープンデータを使って日本地図を描画する

## はじめに

一年ほど前から、仕事で社会課題をICTで解決する企画作りに取り組んでいます。今回は「オープンデータを使って、社会課題の解決につながるものが作れないか」というアプローチで挑戦し、まずは勉強を兼ねて「都道府県ごとの人口の推移を見える化」してみました。(詳細は[こちらのブログ](https://sakinokoto.esm.co.jp/blog-detail/opendata-report-20241113)をご覧ください)

初めてオープンデータを扱ったので、その手順やポイントを備忘録としてまとめていきたいと思います。

## 作ったもの

完成した成果物はこちらです。

1975年から2022年までの都道府県別の総人口データをもとに、1975年を基準年として各年の総人口増減率を色分けして表現しました。白は変化なし、青が濃いほど増加、赤が濃いほど減少を示します。アニメーション化することで、都道府県ごとの総人口推移が一目でわかるようになりました。

![人口推移_base_1975 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919085/a00cf58e-61f7-0ca7-5d63-dcbde537d899.gif)

使用したオープンデータは以下になります。
- 総人口データ：[政府統計の総合窓口(e-Stat)](https://www.e-stat.go.jp/)
- 日本地図のデータ：[国土数値情報（行政区域データ）2024年（令和6年）版（国土交通省）](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html) を加工して作成

また、開発はすべてGoogle Colabで行いました。

## 地図データの作成

アニメーションの一枚一枚は、県で色分けした日本地図の画像です。
まずは都道府県の境界データを含む日本地図のGISデータを[国土数値情報ダウンロードサイト](https://nlftp.mlit.go.jp/)からダウンロードしました。しかし、ダウンロードしたデータはファイルサイズが大きく、地図描画に30秒以上かかります。アニメーション作成のために地図を50回描画すると単純計算で25分かかってしまい、効率がよくありません。1回の地図描画を1秒以内にできるよう、GISデータを加工することにしました。

以下はダウンロードからの手順です。

### 1. ダウンロード
[こちら](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-2024.html)のページから、地域が「全国」のデータをダウンロードして解凍します。
以下は、解凍した`N03-20240101_prefecture.geojson`をそのまま使って描画した日本地図です。この時点ではデータ加工をしていないため、地図の精度は高いですが、描画時間がかかる状態です。

![N03-20240101_prefecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919085/390108a9-0d30-349a-95f7-7dc4f0c2ab36.png)


### 2. 地理情報の単純化
Google Colabで解凍したファイル`N03-20240101_prefecture.geojson`の地理情報を簡略化します。以下のコードを使用しました。
```python
import geopandas as gpd
import matplotlib.pyplot as plt

# ファイルを読み込む
japan_map = gpd.read_file("N03-20240101_prefecture.geojson")

# 都道府県名("N03_001"列)でデータを結合し、県単位のポリゴンにまとめる
japan_map = japan_map.dissolve(by="N03_001")
japan_map.reset_index(inplace=True)

# 必要な列(都道府県名と地理情報)だけを残す
japan_map = japan_map[['N03_001', 'geometry']]

# 地理情報の簡略化を実行（トポロジーを維持しながら許容誤差 0.01 で形状を単純化）
japan_map["geometry"] = japan_map["geometry"].simplify(tolerance=0.01, preserve_topology=True)

# 加工後のデータを保存
japan_map.to_file("japan_p.geojson", driver="GeoJSON")
```
#### 加工前後の地図の比較

以下は、加工前後の地図を比較した画像です(一部を拡大しています)。境界線が少し簡略化されているものの、視覚的にはほとんど変化がなく、クオリティを維持できています。

![比較1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919085/d396f071-19db-0473-dc4f-2303bf4a16d6.jpeg)

#### 改善結果
- ファイルサイズ：321.2MB → 20.4MB（約93%削減）
- 描画時間：33.63秒 → 27.44秒（約18%短縮）

ファイルサイズは大幅に削減できましたが、描画速度はさほど短縮できませんでした。

### 3. さらに簡略化

次に、`Mapshaper`というGISデータ編集ツールを使って、データを簡略化します。MapshaperはGUIツールもありますが、今回はGoogle Colab上でコマンドラインツールを使用しました。
以下のコードで、頂点数を元データの5%に削減しました。

```python
# Node.js をインストール
!curl -sL https://deb.nodesource.com/setup_18.x | sudo -E bash -
!sudo apt-get install -y nodejs

# mapshaper をインストール
!npm install -g mapshaper

# 入力と出力のファイルのパスを指定
input_file = 'japan_p.geojson'
output_file = 'japan_p_simply5.geojson'

# mapshaperで簡略化を実行
# -simplify 5%: 頂点数を元データの5%に削減して形状を簡略化
# -clean: 不要なジオメトリ（重複や孤立した要素など）を削除
!mapshaper {input_file} -simplify 5% -clean -o {output_file}
```

#### 加工前後の地図の比較

以下は、Mapshaper使用前後の地図を比較した画像です。頂点数をかなり削減しましたが、視覚的には問題なく使用可能です。

![比較2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919085/19760ef6-f071-5887-2a91-0e34d9190913.png)

#### 改善結果
- ファイルサイズ：20.4MB → 0.7MB（約97%削減）
- 描画時間：27.44秒 → 0.56秒（約98%短縮）

ファイルサイズ、描画時間ともに大幅に削減できました！

### 4. 地図データ完成

今回の目的に合う実用的なデータができたので、GISデータの加工作業はこれで終了です。
以下は、最終的なGISデータを使って描画した日本地図です。

![japan_p_simply5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919085/8ea8ef6f-8119-b7e7-4727-8fcd1682211e.png)

## 終わりに

今回は、情報量が多すぎる地図データを、自分の目的に合う形へ加工する方法についてまとめました。次回の記事では、この地図データと都道府県別の総人口データを結合し、アニメーションを作るプロセスをご紹介します。