基本的な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から定義書をご参照ください)
plot
全体図
島嶼部を除いた、いつもの東京都の図。
# 全体図 df.plot(figsize=[10,10])
塗り分け図
# 人口で塗り分け df.plot(column="SETAI", legend=True, figsize=[30,10], cmap="Oranges")
# 人口密度で塗り分け df["pop_density"] = df["JINKO"] / df["AREA"] df.plot(column="pop_density", legend=True, figsize=[30,10], cmap="Blues")
一部の地域ですごく高い値がある関係で、ほとんどの地域で薄い色に…
値のラベルをつけた図
# 値ラベル用に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")