シンギュラリティ実験ノート

購入した1000ドルPCで何がどこまでできるのか実験した記録です。

Pythonで日本地図を描く方法

当初はJavaScriptで日本地図を描こうとしたが、AIに頼んでも満足できる結果が得られなかった。マウス操作で拡大縮小できるインタラクティブ性のある詳細な地図は表示できるのだが、今回欲しいのは47都道府県の県境が表示されるシンプルな地図である。

それならPythonで描くほうが簡単かもしれないと思い、まずはPythonで描くことにした。

AIに頼んだり自分で調べるなどしたところ、以下の2つ方法で日本地図を描くことができた。

  • GeoJSONファイルを使用する方法
  • japanmapライブラリを使用する方法

GeoJSONファイルを使用する方法

GeoJSONファイルはこちらにデータが公開されていた。公開されていたデータをPythonで表示した地図がこちら。北方領土はもちろん、小さな島まで表示されている。これはこれで良いのだが、もっと都道府県が大きく表示された分かりやすい地図が欲しいと思った。

 

 

探したところこちら沖縄本島を拡大して移動したデータ”simple_japanmap_02.geojson”が公開されていた。このデータを使い、沖縄本島を囲む枠線を追加して表示した地図がこちら。

 

この地図に統計情報を追加してヒートマップで表現したグラフを作成するPythonのコードをAI(gemma3)に作ってもらった。

AI(gemma3)が作ってくれたPythonのコード
import json
import matplotlib.pyplot as plt
import geopandas as gpd
from matplotlib import rcParams

rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'Noto Sans CJK JP']

def draw_japan_map_with_population_density(geojson_file="simple_japanmap_02.geojson", population_density_data=None):
    """
    日本地図を描画し、都道府県ごとの人口密度をカラーの濃淡で表示する関数

    Args:
        geojson_file (str): GeoJSONファイルのパス。デフォルトは "japan_prefectures.geojson"。
        population_density_data (dict): 人口密度データの辞書。
    """

    try:
        # GeoJSONファイルを読み込む
        gdf = gpd.read_file(geojson_file)

        # 人口密度データの準備
        if population_density_data is None:
            raise ValueError("人口密度データが提供されていません。")

        # 都道府県名の対応付け
        prefecture_names = list(population_density_data.keys())
        density_values = list(population_density_data.values())

        # GeoDataFrameに人口密度を追加
        gdf['population_density'] = 0.0  # 初期化
        for i, name in enumerate(prefecture_names):
            gdf.loc[gdf['prefID'] == name, 'population_density'] = density_values[i]
        
        # カラーマップの準備
        vmin = min(density_values)
        vmax = max(density_values)
        cmap = 'coolwarm'  # カラーマップの選択viridis

        # 地図の描画
        fig, ax = plt.subplots(1, 1, figsize=(10, 10))

        gdf.plot(column='population_density', cmap=cmap, linewidth=0.8, ax=ax, edgecolor='0.8', legend=True, vmin=vmin, vmax=vmax)

        # タイトルと軸ラベルの設定
        ax.set_title('都道府県別人口密度', fontsize=16)
        ax.plot([136.0, 136.0], [44.0, 42.0], color='gray', linewidth=2,)
        ax.plot([136.0, 132.5], [42.0, 39.0], color='gray', linewidth=2,)
        ax.plot([132.5, 129.0], [39.0, 39.0], color='gray', linewidth=2,)

        # 凡例の調整
        cbar = ax.collections[0].colorbar

        # 軸の表示をオフにする
        ax.set_axis_off()

        # 図の表示
        plt.show()

    except FileNotFoundError:
        print(f"エラー: ファイル '{geojson_file}' が見つかりません。")
    except ValueError as e:
        print(f"エラー: {e}")
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")


# テストデータ
population_density_data = {
"01":	60.4,
"02":	122.0,
"03":	75.5,
"04":	307.4,
"05":	78.1,
"06":	109.1,
"07":	127.0,
"08":	450.0,
"09":	288.3,
"10":	287.7,
"11":	1872.9,
"12":	1179.2,
"13":	6129.3,
"14":	3712.2,
"15":	167.4,
"16":	232.3,
"17":	260.6,
"18":	173.9,
"19":	173.7,
"20":	144.8,
"21":	175.8,
"22":	443.4,
"23":	1390.8,
"24":	289.0,
"25":	340.2,
"26":	534.4,
"27":	4454.8,
"28":	624.5,
"29":	346.5,
"30":	187.1,
"31":	151.6,
"32":	95.4,
"33":	254.9,
"34":	316.3,
"35":	209.2,
"36":	165.9,
"37":	484.8,
"38":	224.9,
"39":	92.9,
"40":	1004.6,
"41":	322.0,
"42":	303.5,
"43":	227.4,
"44":	170.1,
"45":	133.4,
"46":	166.8,
"47":	632.2
}


# 関数の呼び出し
draw_japan_map_with_population_density(population_density_data=population_density_data)

 

その実行結果がこちら。都道府県別の人口密度を表示している。単位は1平方キロメートルあたりの人口である。ほとんどの県で300人以下であるのに対し、東京都は6千人以上とダントツに高いため、ヒートマップとしてはわかりにくい図になっている。

人口データは統計データを取得できる下記のサイトから2023年のデータを取得した。

政府統計の総合窓口

都道府県の面積は国土地理院が公表しているようだが、私は下記のサイトから取得した。

47都道府県面積ランキング 日本の国土面積と計測方法も解説 | ELEMINIST(エレミニスト)

 

japanmapライブラリを使用する方法

japanmap という便利なPythonライブラリが公開されている。ヒートマップも手軽に簡単に描くことができる。japanmap を使って描いた都道府県別人口密度のグラフがこちら。

 

japanmap ライブラリを使ったPythonのコード
import numpy as np
import matplotlib.pyplot as plt
import japanmap as jp
from japanmap import picture, get_data, pref_map
from matplotlib.colors import Normalize

# 日本語の都道府県名でデータを作成
population_data = {
    "北海道": 68.6,
    "青森県": 130.5,
    "岩手県": 80.9,
    "宮城県": 320.3,
    "秋田県": 84.4,
    "山形県": 118.9,
    "福島県": 135.0,
    "茨城県": 476.9,
    "栃木県": 307.3,
    "群馬県": 311.4,
    "埼玉県": 1933.4,
    "千葉県": 1216.5,
    "東京都": 6352.8,
    "神奈川県": 3814.5,
    "新潟県": 175.4,
    "富山県": 246.7,
    "石川県": 271.8,
    "福井県": 183.5,
    "山梨県": 182.5,
    "長野県": 152.8,
    "岐阜県": 189.1,
    "静岡県": 473.3,
    "愛知県": 1450.7,
    "三重県": 310.8,
    "滋賀県": 375.5,
    "京都府": 560.1,
    "大阪府": 4644.5,
    "兵庫県": 654.8,
    "奈良県": 363.9,
    "和歌山県": 204.5,
    "鳥取県": 158.3,
    "島根県": 105.3,
    "岡山県": 268.5,
    "広島県": 335.3,
    "山口県": 222.5,
    "徳島県": 178.5,
    "香川県": 511.6,
    "愛媛県": 239.5,
    "高知県": 102.1,
    "福岡県": 1028.5,
    "佐賀県": 332.1,
    "長崎県": 326.4,
    "熊本県": 240.4,
    "大分県": 184.1,
    "宮崎県": 140.3,
    "鹿児島県": 176.8,
    "沖縄県": 639.5
}

temp_color_data = {}

cmap = plt.get_cmap("coolwarm")
norm = Normalize(vmin=min(population_data.values()), vmax=max(population_data.values()))
for pref, temp in population_data.items():
    r, g, b, _ = cmap(norm(temp))  # 色マップからRGBAを取得
    temp_color_data[pref] = (int(r * 255), int(g * 255), int(b * 255))  # RGBへ変換
    
# Create a figure
fig = plt.figure(figsize=(8, 8))

# Remove the axes
ax = plt.Axes(fig, [0., 0., 1., 1.], )
ax.set_axis_off()
fig.add_axes(ax)

plt.title('人口密度')

mappable = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
plt.colorbar(mappable, ax=ax) #axを指定

plt.imshow(jp.picture(temp_color_data),interpolation='nearest')
plt.show()

 

japanmap を使ったPythonコードをAIに書かせたがまともに動くコードはできなかった。japanmap の学習が足りていないようだ。最終的には下記のサイトにあったコードを使わせてもらった。

ChatGPT で Python プログラミング ケーススタディ:日本地図に色を塗る #japanmap - Qiita

 

人口密度の分布

人口密度の分布をヒストグラムで見ると正規分布にはなっていない。このため、平均や標準偏差を求めても意味がなさそうなので、ヒートマップデータには人口密度データを直接使った。

ちなみに入手できた最も古いデータとして1935年のデータがあったので比較してみた。

90年前は今の半分くらいの人口密度であるが、都会への極端な集中という傾向はこのころから変わっていないようだ。