盆暗の学習記録

データサイエンス ,エンジニアリング,ビジネスについて日々学んだことの備忘録としていく予定です。初心者であり独学なので内容には誤りが含まれる可能性が大いにあります。

pythonで塗り分け地図を描く

f:id:nigimitama:20190928225127p:plain

基本的なplotの仕方を覚えたのでメモ。

geopandasによるplot

データの用意

市区町村レベルの行政区域データは国土数値情報の行政区域データから、 町丁レベルの行政区域データはe-Statの境界データダウンロードの小地域データから取得できます。

e-Statの小地域データを例にやってみます

input_path = "shapefile" # 展開先フォルダ名

# e-stat 国勢調査 小地域(町丁・字等別) 東京都全域
shapefile_url = "https://www.e-stat.go.jp/gis/statmap-search/data?dlserveyId=A002005212015&code=13&coordSys=1&format=shape&downloadType=5"
shapefile_name = "tokyo.zip"

# ダウンロード
from urllib.request import urlretrieve
urlretrieve(url=shapefile_url, filename=shapefile_name)

# 解凍
import zipfile
with zipfile.ZipFile(shapefile_name) as existing_zip:
    existing_zip.extractall(input_path)

# ファイル名を取得
import os
files = os.listdir(input_path)
shapefile = [file for file in files if ".shp" in file][0]
print(f"downloaded shapefile: {shapefile}")

# 読み込み
import geopandas as gpd
shapefile_path = os.path.join(input_path, shapefile)
df = gpd.read_file(shapefile_path, encoding='cp932')
print(f"{shapefile_path} is loaded")

# 東京都の島嶼部を除く
import pandas as pd
islands = ['大島町', '利島村', '新島村', '神津島村', '三宅村', '御蔵島村', '八丈町', '青ヶ島村', '小笠原村']
is_not_islands = [df["CITY_NAME"] != island for island in islands]
is_not_islands = pd.concat(is_not_islands, axis=1).all(axis=1)
df = df.loc[is_not_islands, :]

# 陸地だけにする
df = df.loc[df["HCODE"] == 8101, :]

こんな感じのデータです(詳細はe-Statから定義書をご参照ください)

f:id:nigimitama:20190928224557p:plain

plot

全体図

島嶼部を除いた、いつもの東京都の図。

# 全体図
df.plot(figsize=[10,10])

f:id:nigimitama:20190928224655p:plain

塗り分け図

# 人口で塗り分け
df.plot(column="SETAI", legend=True, figsize=[30,10], cmap="Oranges")

f:id:nigimitama:20190928224751p:plain

# 人口密度で塗り分け
df["pop_density"] = df["JINKO"] / df["AREA"]
df.plot(column="pop_density", legend=True, figsize=[30,10], cmap="Blues")

f:id:nigimitama:20190928224833p:plain

一部の地域ですごく高い値がある関係で、ほとんどの地域で薄い色に…

値のラベルをつけた図

# 値ラベル用にgeometryから当該ポリゴン内のある地点を取得
df["coords"] = df["geometry"].apply(lambda x: x.representative_point().coords[:])
df["coords"] = [coords[0] for coords in df["coords"]]

# 文京区の人口密度
temp = df.query("CITY_NAME == '文京区'")
temp.plot(column="pop_density", legend=True, figsize=[30,10], cmap="Blues")

# 値ラベル
import matplotlib.pyplot as plt
for i, row in temp.iterrows():
    plt.annotate(s=round(row["pop_density"], 2), xy=row["coords"], horizontalalignment="center")

f:id:nigimitama:20190928225127p:plain