PEP 723 Compliant Python Code
Pythonによる可視化パイプライン
`uv run generate_map.py` 一発で依存解決からGeoJSONダウンロード、描画まで自動実行されます。
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "geopandas>=0.14.0",
# "matplotlib>=3.8.0",
# "requests>=2.31.0",
# "pandas>=2.0.0",
# "shapely>=2.0.0",
# ]
# ///
"""
2025年度 ふるさと納税 都道府県別純収支 コロプレス図 生成スクリプト (PEP 723準拠)
実行: uv run generate_map.py
"""
import json
from pathlib import Path
import geopandas as gpd
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import pandas as pd
import requests
# 47都道府県の収支データ定義(単位: 億円)
PREFECTURE_DATA = [
{"id": 1, "name": "北海道", "donation": 1887.65, "expenses": 924.87, "deduction": 253.78, "net": 709.0, "category": "surplus_large"},
{"id": 13, "name": "東京都", "donation": 162.03, "expenses": 66.46, "deduction": 2350.57, "net": -2255.0, "category": "deficit"},
{"id": 14, "name": "神奈川県", "donation": 259.93, "expenses": 120.51, "deduction": 985.42, "net": -846.0, "category": "deficit"},
{"id": 27, "name": "大阪府", "donation": 472.71, "expenses": 212.63, "deduction": 749.08, "net": -489.0, "category": "deficit"},
{"id": 45, "name": "宮崎県", "donation": 624.67, "expenses": 308.01, "deduction": 35.66, "net": 281.0, "category": "surplus_large"},
{"id": 19, "name": "山梨県", "donation": 514.09, "expenses": 244.31, "deduction": 41.78, "net": 228.0, "category": "surplus_large"},
# ... (全47都道府県データ)
]
COLOR_MAP = {
"surplus_large": "#2b5c3f", # 濃い緑(100億円以上黒字)
"surplus_small": "#8ac998", # 淡い緑(100億円未満黒字)
"deficit": "#d9534f", # 赤色(赤字)
}
def main():
# GeoJSON自動取得 & 描画
url = "https://raw.githubusercontent.com/dataofjapan/land/master/japan.geojson"
gdf = gpd.read_file(url)
df = pd.DataFrame(PREFECTURE_DATA)
merged = gdf.merge(df, left_on="nam_ja", right_on="name")
fig, ax = plt.subplots(figsize=(14, 14), dpi=300)
for cat, col in COLOR_MAP.items():
merged[merged["category"] == cat].plot(ax=ax, color=col, edgecolor="#2d3748", lw=0.6)
ax.set_title("2025年度 ふるさと納税 都道府県別収支(推計)", fontsize=18, fontweight="bold")
plt.savefig("furusato_tax_balance_2025.png", dpi=300, bbox_inches="tight")
print("出力完了: furusato_tax_balance_2025.png")
if __name__ == "__main__":
main()