全国の人流オープンデータをLeafletで可視化してみる

# オープンデータ

[全国の人流オープンデータ](https://www.geospatial.jp/ckan/dataset/mlit-1km-fromto/resource/1ee9aa41-2980-4801-a218-08acba4737d4)をWebページで可視化する．2019年，2020年，2021年に調査された「1kmメッシュ別の滞在人口データ」と「市区町村単位発生別の滞在人口データ」が提供されている．**滞在人口** とは1ヶ月における1日あたりの人口の平均値を表している．愛知県の2021年の1月～12月のデータはCSV形式のファイルとして公開されている．

- [2021年1月 愛知県 monthly_mdp_mesh1km_1.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_1.csv)
- [2021年2月 愛知県 monthly_mdp_mesh1km_2.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_2.csv)
- [2021年3月 愛知県 monthly_mdp_mesh1km_3.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_3.csv)
- [2021年4月 愛知県 monthly_mdp_mesh1km_4.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_4.csv)
- [2021年5月 愛知県 monthly_mdp_mesh1km_5.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_5.csv)
- [2021年6月 愛知県 monthly_mdp_mesh1km_6.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_6.csv)
- [2021年7月 愛知県 monthly_mdp_mesh1km_7.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_7.csv)
- [2021年8月 愛知県 monthly_mdp_mesh1km_8.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_8.csv)
- [2021年9月 愛知県 monthly_mdp_mesh1km_9.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_9.csv)
- [2021年10月 愛知県 monthly_mdp_mesh1km_10.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_10.csv)
- [2021年11月 愛知県 monthly_mdp_mesh1km_11.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_11.csv)
- [2021年12月 愛知県 monthly_mdp_mesh1km_12.csv](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_12.csv)

CSV形式のデータは次のフィールドで構成される．

- `mesh1kmid`: メッシュID，
- `prefcode`: 都道府県コード
- `citycode`: 市区町村コード
- `year`: 集計期間（年）
- `month`: 集計期間（月）
- `population`: 滞在人口（平均）
- `dayflag`: `0`は休日，`1`は平日，`2`は全日
- `timezone`: `0`は昼，`1`は深夜，`2`は終日

```csvs
mesh1kmid,prefcode,citycode,year,month,dayflag,timezone,population
52365787,23,23101,2021,01,0,0,7154
52365787,23,23101,2021,01,0,1,5054
52365787,23,23101,2021,01,0,2,5985
52365787,23,23101,2021,01,1,0,20313
52365787,23,23101,2021,01,1,1,7110
52365787,23,23101,2021,01,1,2,12750
52365787,23,23101,2021,01,2,0,15219
52365787,23,23101,2021,01,2,1,6314
52365787,23,23101,2021,01,2,2,10131
```

CSV形式のファイルをそのままJavaScriptで読み込むことはできないため，JSON形式のファイルに変換する．変換は次のGoogle Colabのプログラムを利用する．

[CSVtoJSON.ipynb](https://colab.research.google.com/drive/1_GXOXfeaZ0w3tB68EJznOrmLOoBskhdl?usp=sharing)

```json
{
    "mesh1kmid": 52365787, 
    "prefcode": 23, 
    "citycode": 23101, 
    "year": 2021, 
    "month": 1, 
    "dayflag": 0, 
    "timezone": 0, 
    "population": 7154
}
```

- [2021年1月 愛知県 monthly_mdp_mesh1km_1.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_1.json)
- [2021年2月 愛知県 monthly_mdp_mesh1km_2.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_2.json)
- [2021年3月 愛知県 monthly_mdp_mesh1km_3.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_3.json)
- [2021年4月 愛知県 monthly_mdp_mesh1km_4.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_4.json)
- [2021年5月 愛知県 monthly_mdp_mesh1km_5.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_5.json)
- [2021年6月 愛知県 monthly_mdp_mesh1km_6.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_6.json)
- [2021年7月 愛知県 monthly_mdp_mesh1km_7.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_7.json)
- [2021年8月 愛知県 monthly_mdp_mesh1km_8.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_8.json)
- [2021年9月 愛知県 monthly_mdp_mesh1km_9.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_9.json)
- [2021年10月 愛知県 monthly_mdp_mesh1km_10.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_10.json)
- [2021年11月 愛知県 monthly_mdp_mesh1km_11.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_11.json)
- [2021年12月 愛知県 monthly_mdp_mesh1km_12.json](https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_12.json)

# 開発環境

開発環境として[CodePen](https://codepen.io/)を利用する．ここでは次のライブラリを利用する．

- オンライン地図のライブラリ [Leaflet](https://leafletjs.com/)
- コーディングを支援するライブラリ [jQuery](https://jquery.com/)
- 地域メッシュコードを処理するライブラリ [jismesh-js](https://github.com/yoshizow/jismesh-js)

Penを新規作成し，`Settings -> JS`でライブラリをCDN(Content Delivery Network)で導入する．このとき，`https://unpkg.com/jismesh-js/dist/jismesh.min.js`は直接入力する．

[![Image from Gyazo](https://i.gyazo.com/2ce3c6f43cea7718cb6b889d1fcdae59.png)](https://gyazo.com/2ce3c6f43cea7718cb6b889d1fcdae59)

同様にLeafletのCSSを`Settings -> CSS`から追加する．

`https://unpkg.com/leaflet@1.7.1/dist/leaflet.css`

[![Image from Gyazo](https://i.gyazo.com/d52ea5ecdb3ba1dc405493a55c92b19c.png)](https://gyazo.com/d52ea5ecdb3ba1dc405493a55c92b19c)

# ソースコード

## HTML

`div`要素を作成する．`id`属性には`map`を設定する．

```html
<div id="map"></div>
```

## CSS 

地図を全画面表示するための設定を記述する．`html`要素と`body`要素の高さを`100%`に設定する．`id`属性が`map`の高さを`100%`に設定する．

```css
html, body{
  height: 100%;
}

#map{
  height: 100%;
}
```

## JavaScript

`$.getJSON()`で人流オープンデータを読み込む．検索対象の平休日（`dayflag`）と時間帯（`timezone`）をフィルタし，`flow_list`に追加する．メッシュコード（標準メッシュコード）は1辺が1kmの矩形領域を表す．このため，矩形の四隅の緯度・経度を算出し，マーカー（`L.rectangle`）を生成して表示する．

```javascript
const tile = "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
const attribution = "&copy; <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap</a> contributors";
const flow_url = "https://mukai-lab.info/classes/graduation_preperation_1/jinryuu/aichi_2021/monthly_mdp_mesh1km_1.json";

let lat = 35.1706431 ; // 緯度
let lon = 136.8816945; // 経度
let zoom = 10; // ズームレベル

// 地図
let map = L.map("map");

// 緯度・経度・ズームレベルの設定
map.setView([lat, lon], zoom);

// タイルを地図に追加
L.tileLayer(tile, 
  {
    attribution: attribution
  }
).addTo(map);

// 人流データのリスト
let flow_list = [];

// 検索対象の平休日と時間帯
let target_dayflag = 2; // 全日
let target_timezone = 2; // 終日

// 滞在人口の基準値
let threshold = 10000;

// JSONファイルの読込
$.getJSON(flow_url, (data) => {

  // 対象の人流データを取得
  for(let flow of data){
    if(flow["dayflag"] == target_dayflag && flow["timezone"] == target_timezone){
      flow_list.push(flow);
    }
  }
  
  // メッシュの座標でマーカーを生成
  for(let flow of flow_list){
    let meshcode = flow["mesh1kmid"]; // メッシュコード
    let population = flow["population"]; // 滞在人口（平均）
    
    // マーカーの緯度経度を算出
    let [lat1, lon1] = jismesh.toMeshPoint(meshcode, 0, 0); // 南西の緯度経度
    let [lat2, lon2] = jismesh.toMeshPoint(meshcode, 0, 1); // 東南の緯度経度
    let [lat3, lon3] = jismesh.toMeshPoint(meshcode, 1, 0);　// 北西の緯度経度
    let [lat4, lon4] = jismesh.toMeshPoint(meshcode, 1, 1); // 北東の緯度経度
    bounds = [[lat1, lon1], [lat2, lon2], [lat3, lon3], [lat4, lon4]]
    
    // マーカーの色を設定
    let option;
    if(population >= threshold){
      option = {
        "color": "red",
        "fillColor": "red"
      }
    }
    else{
     option = {
        "color": "blue",
        "fillColor": "blue"
      } 
    }
    
    // マーカーを追加
    let marker = L.rectangle(bounds, option);
    marker.addTo(map);
  }
  
});
```

# デモ

<p class="codepen" data-height="300" data-default-tab="js,result" data-slug-hash="RwJEqza" data-user="nmukai" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/nmukai/pen/RwJEqza">
  PeopleFlowMap</a> by Naoto Mukai (<a href="https://codepen.io/nmukai">@nmukai</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>