Google Mapで将来推計人口メッシュデータのGeoJSONを読み込み、人口推移を可視化してみる

## はじめに
将来推計人口メッシュデータのGeoJSONファイルを元にして、5年毎に推計されている人口の推移をGoogle Mapの地図上で可視化してみました。
## 将来推計人口データ
国立社会保障・人口問題研究所(社人研)が「コーホート要因法」で推計した「日本の地域別将来推計人口」をベースにして、マップマーケティングで作成しているデータ（未来人口データ2020）を利用しています。

https://www.mapmarketing.co.jp/data/tokei/future_population.html?grid=qiita&utm_source=qiita.com&utm_medium=referral&utm_campaign=qiita_select_future_populations_on_gmap_e0fbafda20b115cab33e_01
### GeoJSONファイル（抜粋）
2020年人口総数、2025～2050年の将来推計人口を属性に持つGeoJSONファイルについては、[TerraMap API](https://www.mapmarketing.co.jp/terramap-api?grid=qiita&utm_source=qiita.com&utm_medium=referral&utm_campaign=qiita_select_future_populations_on_gmap_e0fbafda20b115cab33e_02)から取得できるものを利用しました。ポリゴンに関しては人口密集地域とその推移がはっきり分かるように「2分の1地域メッシュ(約500mメッシュ)」を選択しました。
```future-populations.geojson
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "area": {
          "area": 0.26165750865507126,
          "ratio_area": [
            0.26165750865507126
          ],
          "ratio": [
            1.0
          ]
        },
        "data": [
          {
            "is_authorized": true,
            "ratio_value": [
              "4633"
            ],
            "stat_item_id": 23098,
            "stat_id": "029002300",
            "value": "4633"
          },
          {
            "is_authorized": true,
            "ratio_value": [
              "4670"
            ],
            "stat_item_id": 23099,
            "stat_id": "029002300",
            "value": "4670"
          },

          // .... 将来推計人口データを省略しています
        ],
        "point_coordinates": [
          139.615625,
          35.652083333
        ],
        "geocode": "533934891",
        "points": []
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [
                139.61875,
                35.65
              ],
              [
                139.6125,
                35.65
              ],
              [
                139.6125,
                35.654166667
              ],
              [
                139.61875,
                35.654166667
              ],
              [
                139.61875,
                35.65
              ]
            ]
          ]
        ]
      }
    },

    // .... featureを省略しています
```

## GeoJSONの表示と切り替え処理
今回は少し前に書きました以下記事のソースをアレンジし作成してみました。変更点を中心にコメントで補足しているので、1度みていただいた方がより理解しやすいかと思います。

https://qiita.com/y-mto/items/816f1bc92f8d7f835074

### HTML
※Google Mapを表示するには、Google Maps Platform用のAPIキーが必要となります。
```index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <title>
      Google Map上に将来推計人口のメッシュデータを表示してみる
    </title>
    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <!--
    将来推計人口を選択するselectタグを追加
    valueは人口データを特定するID -->
    <select id="future-population-select">
      <option value="23098">(基準)2020年人口総数</option>
      <option value="23099">2025年人口総数</option>
      <option value="23100">2030年人口総数</option>
      <option value="23101">2035年人口総数</option>
      <option value="23102">2040年人口総数</option>
      <option value="23103">2045年人口総数</option>
      <option value="23104">2050年人口総数</option>
    </select>
    <div id="map"></div>
    <div id="legend"></div>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "YOUR_GOOGLE_MAP_API_KEY", v: "weekly"});</script>
  </body>
</html>
```
### JavaScript
```index.js
let map;
let geoJsonLayer;    // GeoJSONレイヤーの宣言

// 人口総数による配色
function getColor(d) {
  return d > 7000
    ? "#8b0000"
    : d > 6000
    ? "#d7352b"
    : d > 5000
    ? "#ffa746"
    : d > 4000
    ? "#ffd976"
    : d > 3000
    ? "#c9d0bb"
    : d > 2000
    ? "#92c7ff"
    : d > 1000
    ? "#5b97ee"
    : "#0855c4";
}

// 人口データIDに応じてフィーチャのスタイル設定を取得
function getPolygonStyleOptions(feature, populationId) {
  // 複数の人口データから1つを取得
  const dataItem = feature.getProperty("data").find(item => item.stat_item_id == populationId);
  return {
    strokeColor: "black",
    strokeOpacity: 1.0,
    strokeWeight: 0.5,
    fillColor: getColor(dataItem.value),  // 取得した人口データに応じた色を取得
    fillOpacity: 0.5,
  };
}

// 人口データIDに応じてGeoJSONレイヤーのスタイルを設定
function setLayerStyleByPopulationId(populationId) {
  geoJsonLayer.setStyle(feature => {
    return getPolygonStyleOptions(feature, populationId);
  });
}

async function initMap() {
  const { Map } = await google.maps.importLibrary("maps");
  const centerLocation = { lat: 35.681236, lng: 139.767124 };

  map = new Map(document.getElementById("map"), {
    center: centerLocation,
    zoom: 11,
    disableDefaultUI: true,  // 地図のUIはシンプルに
  });

  // レイヤーにGeoJSONをロードする
  geoJsonLayer = new google.maps.Data();
  geoJsonLayer.setMap(map);
  geoJsonLayer.loadGeoJson("./future-populations.json");

  // selectの変更に応じてスタイルを更新
  document.getElementById('future-population-select').addEventListener('change', function() {
    setLayerStyleByPopulationId(this.value);
  });

  // スタイルの初期値「(基準)2020年人口総数」
  setLayerStyleByPopulationId("23098")

  // 凡例の表示
  const legend = document.getElementById("legend");
  const grades = [0, 1000, 2000, 3000, 4000, 5000, 6000, 7000];

  for (let i = 0; i < grades.length; i += 1) {
    const from = grades[i];
    const to = grades[i + 1];

    const div = document.createElement("div");
    div.className = "info";
    div.innerHTML = `<span style="background:${getColor(from + 1)}"></span> ${from}${
      to ? `&ndash;${to}` : "+"
    }`;
    legend.appendChild(div);
  }

  map.controls[google.maps.ControlPosition.RIGHT_BOTTOM].push(legend);
}

initMap();

```

### CSS
```style.css
/* 凡例関係 */
#legend {
  font: 12px Arial, Helvetica, sans-serif;
  background: rgba(255, 255, 255, 0.8);
  padding: 10px;
  margin: 10px;
  box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
  border-radius: 5px;
}

#legend span {
  width: 15px;
  height: 15px;
  float: left;
  margin-right: 8px;
  opacity: 0.7;
}

#legend .info {
  width: 90px;
  height: 15px;
}

/* 地図サイズ */
#map {
  width: 100%;
  height: calc(100vh - 60px);
}

/* select */
#future-population-select {
  font-size: 18px;
  padding: 5px;
  margin: 5px 0px;
  width: 300px;
}
```

## 表示結果
メッシュデータを東京駅周辺に限定させて、5年毎の将来推計人口を切り替えてみると以下のようになりました。

![select-future-populations2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2893989/08def054-ad6e-d34f-bb11-228d3e4f32b0.gif)

表示させて切り替えてみると、2040年までは人口密集地域がはっきりと拡大、2045年・2050年では比較的ゆるやかな変化になっていることが見て取れます。かなり先の推計値ではありますが、このころの東京はどうなっているのでしょうか？

記事は以上になります。ありがとうございました。