Pythonで地理データをマッピング:小山市と栃木市を可視化する方法

地理空間データを使った分析や可視化は、データ分析スキルをさらに向上させる手段の一つです。この記事では、Pythonを使って、小山市と栃木市に関するデータを可視化する方法を解説します。作業はgoogleのcolabで実施しました。


使用したデータ

  • e-stat(政府統計の総合窓口)

    • 年齢(5歳階級、4区分)別、男女別人口データ: こちら

    • 地域別コードに基づいた栃木県の境界データ: こちら

  • 国土数値情報(国土交通省)

------------------------------------

必要なライブラリ

以下のライブラリを使用します。事前にインストールしてください。

pip install geopandas pandas folium pyproj shapely

ステップ1:データの読み込み

Google Driveに保存されたデータを読み込みます。

from google.colab import drive
import geopandas as gpd
import pandas as pd

# Google Driveをマウント
drive.mount('/content/drive')

# ファイルパス設定
csv_path = '/path_to_population_data.csv'
shp_path = '/path_to_town_boundary.shp'
station_path = '/path_to_station_data.geojson'
land_price_path_1 = '/path_to_land_price_1.geojson'
land_price_path_2 = '/path_to_land_price_2.geojson'
flood_path = '/path_to_flood_data.geojson'

# 各データを読み込む
population_df = pd.read_csv(csv_path, encoding='shift_jis')  # 人口データ
town_gdf = gpd.read_file(shp_path)  # 町丁字ポリゴン
station_gdf = gpd.read_file(station_path)  # 駅データ
land_price_gdf_1 = gpd.read_file(land_price_path_1)  # 公示地価1
land_price_gdf_2 = gpd.read_file(land_price_path_2)  # 公示地価2
flood_gdf = gpd.read_file(flood_path)  # 洪水浸水想定区域

ステップ2:座標系の統一

データの座標系が異なる場合、統一する必要があります。ここではすべて「EPSG:4326」に変換します。

# 座標系を統一(EPSG:4326)
target_crs = 'EPSG:4326'
town_gdf = town_gdf.to_crs(target_crs)
station_gdf = station_gdf.to_crs(target_crs)
land_price_gdf_1 = land_price_gdf_1.to_crs(target_crs)
land_price_gdf_2 = land_price_gdf_2.to_crs(target_crs)
flood_gdf = flood_gdf.to_crs(target_crs)

ステップ3:データの加工

人口データと町丁字データの結合

人口データを町丁字ポリゴンに結合し、人口密度を計算します。

# 町丁字コードを統一フォーマットに変換
population_df['町丁字コード_修正'] = population_df['町丁字コード'].apply(lambda x: f"{int(x):06}")

# ポリゴンデータと人口データを結合
merged_gdf = town_gdf.merge(population_df, left_on='S_AREA', right_on='町丁字コード_修正', how='left')

# 面積と人口密度を計算(平面座標系で面積計算後、再度EPSG:4326に戻す)
projected_gdf = merged_gdf.to_crs(epsg=3857)
projected_gdf['面積m2'] = projected_gdf.geometry.area
merged_gdf = projected_gdf.to_crs(epsg=4326)
merged_gdf['人口密度'] = merged_gdf['総数'] / merged_gdf['面積m2']

工夫した点

  • 平面座標系での面積計算を取り入れ、より正確な人口密度を算出。


小山市と栃木市のデータを抽出

対象地域を「小山市」と「栃木市」に絞り込みます。

# 小山市と栃木市のポリゴンを抽出
target_cities = ['小山市', '栃木市']
oyama_tochigi_gdf = town_gdf[town_gdf['CITY_NAME'].isin(target_cities)]

# 各データを対象地域にクリップ
merged_gdf = gpd.clip(merged_gdf, oyama_tochigi_gdf)
station_gdf = gpd.clip(station_gdf, oyama_tochigi_gdf)
land_price_gdf_1 = gpd.clip(land_price_gdf_1, oyama_tochigi_gdf)
land_price_gdf_2 = gpd.clip(land_price_gdf_2, oyama_tochigi_gdf)
flood_gdf = gpd.clip(flood_gdf, oyama_tochigi_gdf)

工夫した点

  • gpd.clipを活用して効率的に対象地域に限定。これでストレスなくデータを表示することが可能になります


ステップ4:地図の作成

地図の初期化

地図の中心座標を計算し、Foliumで地図を初期化します。

from pyproj import Transformer
import folium

# 中心座標の計算
projected_gdf = merged_gdf.to_crs(epsg=3857)
center_x = projected_gdf.geometry.centroid.x.mean()
center_y = projected_gdf.geometry.centroid.y.mean()
transformer = Transformer.from_crs("EPSG:3857", "EPSG:4326", always_xy=True)
center_lon, center_lat = transformer.transform(center_x, center_y)

# 地図の作成
m = folium.Map(location=[center_lat, center_lon], zoom_start=12, tiles='cartodbpositron')

人口密度の表示

人口密度をChoroplethで可視化します。

folium.Choropleth(
    geo_data=merged_gdf,
    data=merged_gdf,
    columns=['S_AREA', '人口密度'],
    key_on='feature.properties.S_AREA',
    fill_color='YlOrRd',
    fill_opacity=0.3,  # 透過度を調整
    line_opacity=0.2,
    legend_name='人口密度(人/m²)',
    name='人口密度レイヤー'
).add_to(m)

駅情報の表示

駅名と乗降客数をマーカーで表示します。

stations_layer = folium.FeatureGroup(name='駅情報', show=True)
for idx, row in station_gdf.iterrows():
    folium.Marker(
        location=[row.geometry.y, row.geometry.x],
        popup=f"駅名: {row['S12_001']}<br>乗降客数: {row['S12_053']}",
        icon=folium.Icon(color='blue', icon='train', prefix='fa')
    ).add_to(stations_layer)
stations_layer.add_to(m)

洪水浸水想定区域の表示

浸水深ランクに応じた色分けを行います。

flood_colors = {1: 'lightblue', 2: 'blue', 3: 'purple', 4: 'red', 5: 'brown', 6: 'black'}

def flood_style(feature):
    code = feature['properties']['A31b_101']
    return {'fillColor': flood_colors.get(code, 'gray'), 'fillOpacity': 0.4}

flood_layer = folium.FeatureGroup(name='洪水浸水想定区域', show=False)
folium.GeoJson(flood_gdf, style_function=flood_style).add_to(flood_layer)
flood_layer.add_to(m)

地図の保存

作成した地図をHTMLとして保存します。

m.save('map.html')

おわりに

小山市と栃木市を対象に、Pythonで地理データを可視化する方法を紹介しました。特に以下の点で工夫を施しました:

  1. 平面座標系を利用した面積計算で正確な人口密度を算出

  2. 効率的な地域クリップ処理でデータ量を削減

  3. 浸水深ランク別の色分け表示で視覚的な情報提供

他の地域やデータセットでも試してみてください。

いいなと思ったら応援しよう!