Leaflet で福井県の年度別市町村人口を出してみた
前回の記事
白地図を出すだけでは芸がないので、福井県の年度別市町村人口を表示してみました。表示するときは、少しデータの取得に時間がかかります。10秒も待てば終わると思います。
だいたいこんな感じです。
市区町村の人口を出すにあたってやったことは、大きく分けて2つです。
- 人口に応じて市区町村の色を変える
- 年度を切り替えられるようにする
人口データは福井県のオープンデータ「市町別・年齢別・男女別人口 」を使っています。
人口に応じて市区町村の色を変える
L.getJSON
の第2引数に style
関数を渡すことで、何かの数字に応じて色を変えることができます。この関数が人口に応じた色の設定を返します。ポイントは fillColor
を population
に応じて変えているところです。
引数などの細かい条件はドキュメントに詳しく書いてあります。
let populations = [] function style(feature) { const mname = mcodeToNameMap[feature.properties.municipality_code]; const population = populations.reduce((p, row) => { if (row[2] === mname) p += row[4] return p }, 0) console.log(`${mname} => ${population}`) return { weight: 2, dashArray: '3', fillColor: population > 100000 ? '#800026' : population > 80000 ? '#BD0026' : population > 60000 ? '#E31A1C' : population > 40000 ? '#FC4E2A' : population > 30000 ? '#FD8D3C' : population > 20000 ? '#FEB24C' : population > 10000 ? '#FED976' : '#FFEDA0' } } const g = L.geoJSON(geojson, { style }).addTo(mymap);
年度を切り替えられるようにする
人口データは2010年から2015年にかけて6年分のデータが入っているので、せっかくだから年度を切り替えて表示できるようにしました。
const yearEl = document.querySelector('#year') rxjs.fromEvent(yearEl, 'change') .subscribe(() => { updateYear(Number(yearEl.value)) }) function updateYear(year) { google.script.run.withSuccessHandler((p) => { populations = p console.log(populations); g.eachLayer(l => g.resetStyle(l)) }).getPopulations(year); }
range input を動かしたら updateYear
を呼び出して populations
を更新し、地図の見た目を更新しています。地図の見た目は g.eachLayer(l => g.resetStyle(l))
で更新することができます。これで style
関数が再評価されるようです。イベント処理に RxJS を使っていますが深い意味はないです。
ここの実装については公式サンプルの Interactive Choropleth Map が参考になりました。
まとめ
これらをまとめた一連の実装です。全市区町村の geojson から、ある都道府県の市区町村だけを抽出するコードとか、市区町村の名前とコード (MstMunicipality.code
) を対応付けるコードとか、本質でないコードもあるので、少し長めです。
(function () { let mymap = L.map('mapid').setView([35.8, 136.5], 8); // これらの cache-control ヘッダーでキャッシュが禁止されている。 Promise.all([ // 市区町村の形状データ fetch('https://www.itdashboard.go.jp/js/data/municipality.geojson').then(resp => resp.json()), // 都道府県と市区町村の対応付データ fetch('https://www.itdashboard.go.jp/Api/getData.json?dataset=MstMunicipality').then(resp =>resp.json()) ]).then(([geojson, municipalities]) => { return extractPrefecture(geojson, municipalities, '18') }).then(([geojson, municipalities]) => { const mcodeToNameMap = municipalities.reduce((map, value) => { map[value.MstMunicipality.code] = value.MstMunicipality.name; return map; }, {}) let populations = [] function style(feature) { const mname = mcodeToNameMap[feature.properties.municipality_code]; const population = populations.reduce((p, row) => { if (row[2] === mname) p += row[4] return p }, 0) console.log(`${mname} => ${population}`) return { weight: 2, dashArray: '3', fillColor: population > 100000 ? '#800026' : population > 80000 ? '#BD0026' : population > 60000 ? '#E31A1C' : population > 40000 ? '#FC4E2A' : population > 30000 ? '#FD8D3C' : population > 20000 ? '#FEB24C' : population > 10000 ? '#FED976' : '#FFEDA0' } } const g = L.geoJSON(geojson, { style }).addTo(mymap); updateYear(2015); const yearEl = document.querySelector('#year') rxjs.fromEvent(yearEl, 'change') .subscribe(() => { updateYear(Number(yearEl.value)) }) function updateYear(year) { google.script.run.withSuccessHandler((p) => { populations = p console.log(populations); g.eachLayer(l => g.resetStyle(l)) }).getPopulations(year); } }) function extractPrefecture(geojson, municipalities, prefectureCode) { // MstMunicipality: { // code: string, // name: string, // re_code: string, // re_name: string // } const extractedMunicipalities = municipalities.raw_data.filter(d => d.MstMunicipality.re_code ===prefectureCode) const mcodes = extractedMunicipalities.map(d => Number(d.MstMunicipality.code)) const extractedGeojson = { ...geojson, features: geojson.features.filter(feature => mcodes.indexOf(feature.properties.municipality_code)!== -1) } return [extractedGeojson, extractedMunicipalities] } })()
(6/1 追記)
これは Google Apps Script (GAS) でホスティングしている HTML で実装しました。途中で唐突に google.script.run
が出てくるのはそのためです。福井県の年度別市町村人口をシートに転記して、それを GAS で作った getPopulations
関数経由で読み込んでいます。
GAS 側のコードはこれだけです。
function doGet() { return HtmlService.createHtmlOutputFromFile('map') } function getPopulations(year) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet() var range = sheet.getRange(2, 1, sheet.getMaxRows() - 1, 7); var rows = range.getValues(); var results = []; for (var i = 0; i < rows.length; i++) { if (rows[i][0] != String(year)) continue; results.push(rows[i]); } return results; }