Python
geojson
Visualization
Jupyter
Cesium

Jupyter Notebook上で3Dコロプレスマップを描写

はじめに

  • 値に応じて市区町村および都道府県が浮き上がる3DコロプレスマップをNotebook上で描写してみた
  • 参考資料が少なくちょっと手間取ったので備忘録としてまとめておく
  • 今回使用したコードはgithubにアップロードしておく

ポイント

描写例

figure.GIF

動かしてみた

  • 今回の動作環境
    • クライアント(Windows 10 Pro)
      • ブラウザ : Google Chrome 68.0.3440.106
        (Microsoft Edge, Firefoxでは動作しなかった)
    • サーバ(Ubuntu 18 on VMware Workstation 12 Player)
      • JupyterLab : 0.33.11
      • python : 3.6
      • cesiumpy : 0.3.3

準備

  • cesiumpyのインストール
  • GeoJsonのダウンロード
  • (Jupyter Notebookの環境は構築済みとする)
! pip install cesiumpy
import cesiumpy

群馬県を描写(デフォルト設定)

#群馬
v = cesiumpy.Viewer()

#geojsonを読み込み座標棟を取得
res = cesiumpy.io.read_geojson('./geojson/prefectures/10.json')

#グラフの値をextrudedHeightとすることで値に応じてポリゴンを浮き出させる
myExtrudedHeight = 10e3

#エンティティーへ設定
v.entities.add(res, extrudedHeight=myExtrudedHeight)

#描写
v

1.GIF

群馬県を描写(カスタム)

  • 本家のCesium.jsと同様に各種プロパティを変更可能
  • ラッパーが対応していない機能も一部あるようなので注意
#ウィジェットの有無は辞書型で渡すので注意
options = dict(\
               animation=False,\
               timeline=False,\
               fullscreenButton=False,\
              )
#グンマ
v = cesiumpy.Viewer(**options)
res = cesiumpy.io.read_geojson('./geojson/prefectures/10.json')
myExtrudedHeight = 10e3
#各種プロパティの設定
myName = '群馬県'
myDescription = 'I love Gunma'
myMaterial = cesiumpy.color.Color.fromCssColorString('pink').withAlpha(0.8)
myOutlineColor = cesiumpy.color.Color.fromCssColorString('#FF0000')
v.entities.add(\
               res,\
               name = myName,\
#おそらくdescriptionは非対応
               description=myDescription,\
               extrudedHeight = myExtrudedHeight,\
               material = myMaterial,\
               outline  =True,\
               outlineColor = myOutlineColor,\
              )
v

2.GIF

群馬県を描写(市区町村別)

  • 市区町村単位でGeoJsonを読み込めばよい
  • 元データは行政区域単位で用意されており、行政区域コードがファイル名である
  • 市区町村名と行政区域コードを対応付けたJsonファイルを用意しておくと管理しやすい
import json
import os
import random
#市区町村名と行政区域コードを対応付けたJsonファイルを読み込む
with open('./myList.json') as f:
    ml = json.load(f)
f.close()
#行政区域コードからディレクトリを判別する関数
def setDir(code):
    n = int(code)
    if (n > 1000):
        return code[0:2]
    else:
        return "mergedPrefectures"
#Entitiyを1つ追加する関数(引数:行政区域コード,値,色,輪郭色)
def setEntitiy(code,val,rgb1,rgb2):
    path = './geojson/'+setDir(code)+'/'+code+'.json'
    res = cesiumpy.io.read_geojson(path)
    myName = ml[code]
    myMaterial = cesiumpy.color.Color.fromCssColorString(rgb1)
    myOutlineColor = cesiumpy.color.Color.fromCssColorString(rgb2)
    v.entities.add(res,\
                   name=myName,\
                   extrudedHeight=val,\
                   material=myMaterial,\
                   outline=True,\
                   outlineColor=myOutlineColor)
#ディレクトリ内のgeojsonをすべて描写する関数(値も色もランダム)
def setRandomEntities(code):
    list = []
    path = 'geojson/'+code
    for file in os.listdir(path):
        base, ext = os.path.splitext(file)
        if ext == '.json':
            list.append(base)
    list.sort()
    for i in list:
        val = random.randrange(10e3)
        clr = '#C'+str(val).zfill(5)
        setEntitiy(i,val,clr,clr)
#グンマー
v = cesiumpy.Viewer(**options)
setRandomEntities('10')
v

3.GIF

日本全国を描写

描写失敗

  • GeoJsonのデータが大きすぎてブラウザが停止 error.GIF

GeoJsonのサイズダウン

A) 都道府県境のみを抽出

  • 都道府県のグラフであれば市区町村の区分は不要
  • QGISというGISソフトウェアを利用して結合
  • 手順
    1. QGISにGeoJsonファイルをドラッグ&ドロップ
    2. [ベクター]>[空間演算ツール]>[ディゾルブ]をクリックQGIS1.png
    3. [パラメーター]>[入力レイヤ]>[...]へ変換したいGeoJsonのレイヤを設定
    4. [パラメーター]>[融合]>[...]>[Save to File]から出力先及びファイル形式(geojson)を設定QGIS2.png
    5. [バックグラウンドで実行]をクリック
      (複数ある場合には[Run as Batch Process]から一括処理も可能)
    6. 拡張子を「geojson」から「json」に書き換える

B) GeoJsonの簡素化

  • 結合してもデータ量は大きい
  • ポリゴンの点数そのものを減らすことで処理速度の向上
  • mapshaperサイトというが目視して調整でき利用しやすい(QGISでも簡素化可能)
    1. [mapshaper]にGeoJsonファイルをドラッグ&ドロップmapshaper1.png
    2. 必要な[Option]を選択して[Import]mapshaper2.png
    3. [Simplify]をクリックして、必要な[Simplification menu]を選択mapshaper3.png
    4. [Settings]の倍率を調整して整形
    5. [Export]をクリック、[GeoJson]を選択mapshaper4.png
    6. 完了

描写成功

#日本
v = cesiumpy.Viewer(**options)
for i in range(1,48):
    val = random.randrange(10e4)
    clr = '#E'+str(val).zfill(5)
    setEntitiy(str(i).zfill(2),val,clr,clr)
v

4.GIF

終わりに

  • GeoJsonをサイズダウンすることで3Dコロプレスマップを描写することができた
  • Notebook上で動作することが最大のメリットである
    • スクレイピングなどと併用するとその真価が発揮する
    • 集計から整形、描写までNotebook(Python)で完結する