{"spec_id":"choropleth-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nchoropleth-basic: Choropleth Map with Regional Coloring\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 81/100 | Updated: 2026-05-15\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    coord_fixed,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_polygon,\n    geom_text,\n    ggplot,\n    labs,\n    scale_fill_cmap,\n    theme,\n)\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nMISSING_DATA_COLOR = \"#A9A9A9\" if THEME == \"light\" else \"#696969\"\n\nnp.random.seed(42)\n\n# Simplified European country boundaries (approximate polygon coordinates)\ncountries = {\n    \"France\": [(0, 0), (3, 0), (4, 2), (3, 4), (1, 4), (0, 2)],\n    \"Germany\": [(4, 2), (7, 1), (8, 3), (7, 5), (4, 5), (3, 4)],\n    \"Spain\": [(-3, -3), (1, -3), (2, -1), (0, 0), (-2, 0), (-3, -1)],\n    \"Italy\": [(5, -2), (7, -3), (9, -1), (8, 2), (6, 1), (5, 0)],\n    \"Poland\": [(8, 3), (12, 2), (13, 5), (11, 6), (8, 5), (7, 5)],\n    \"UK\": [(-2, 4), (1, 4), (2, 6), (1, 8), (-1, 8), (-2, 6)],\n    \"Sweden\": [(7, 7), (10, 6), (11, 9), (10, 12), (8, 11), (7, 9)],\n    \"Norway\": [(5, 9), (7, 7), (8, 11), (7, 14), (5, 13), (4, 11)],\n    \"Finland\": [(11, 9), (14, 8), (15, 12), (13, 14), (11, 12), (10, 12)],\n    \"Austria\": [(6, 1), (8, 0), (10, 1), (9, 3), (7, 3), (6, 2)],\n    \"Netherlands\": [(2, 5), (4, 5), (5, 6), (4, 7), (2, 7), (1, 6)],\n    \"Belgium\": [(1, 4), (3, 4), (4, 5), (2, 5), (1, 5)],\n    \"Switzerland\": [(3, 1), (5, 0), (6, 1), (5, 2), (4, 2), (3, 2)],\n    \"Portugal\": [(-4, -2), (-3, -3), (-2, -1), (-3, 0), (-4, 0)],\n    \"Denmark\": [(5, 6), (7, 5), (8, 6), (7, 7), (5, 7)],\n    \"Czechia\": [(7, 3), (9, 3), (10, 4), (9, 5), (7, 5), (6, 4)],\n}\n\n# Life expectancy at birth (years) - realistic values for 2023-2024\n# Czechia has None to demonstrate missing data handling\nlife_expectancy = {\n    \"France\": 82.4,\n    \"Germany\": 81.8,\n    \"Spain\": 83.1,\n    \"Italy\": 83.5,\n    \"Poland\": 78.0,\n    \"UK\": 81.3,\n    \"Sweden\": 84.2,\n    \"Norway\": 84.6,\n    \"Finland\": 82.5,\n    \"Austria\": 81.9,\n    \"Netherlands\": 82.1,\n    \"Belgium\": 81.8,\n    \"Switzerland\": 84.0,\n    \"Portugal\": 82.2,\n    \"Denmark\": 81.5,\n    \"Czechia\": None,\n}\n\n# Build polygon dataframe\npolygon_data = []\nfor country, coords in countries.items():\n    closed_coords = coords + [coords[0]]\n    for i, (x, y) in enumerate(closed_coords):\n        polygon_data.append(\n            {\"country\": country, \"x\": x, \"y\": y, \"order\": i, \"life_expectancy\": life_expectancy[country]}\n        )\n\ndf = pd.DataFrame(polygon_data)\n\n# Calculate centroids for country labels\nlabel_offsets = {\n    \"Netherlands\": (0.5, 1.0),\n    \"Belgium\": (-0.8, -0.5),\n    \"Germany\": (0.5, -0.5),\n    \"Denmark\": (0.5, 0.5),\n    \"Czechia\": (0, -0.5),\n}\n\ncentroids = []\nfor country, coords in countries.items():\n    cx = np.mean([c[0] for c in coords])\n    cy = np.mean([c[1] for c in coords])\n    if country in label_offsets:\n        cx += label_offsets[country][0]\n        cy += label_offsets[country][1]\n    expectancy = life_expectancy[country]\n    centroids.append({\"country\": country, \"x\": cx, \"y\": cy, \"life_expectancy\": expectancy})\n\ndf_centroids = pd.DataFrame(centroids)\n\n# Separate data with and without values for missing data handling\ndf_with_data = df[df[\"life_expectancy\"].notna()].copy()\ndf_missing = df[df[\"life_expectancy\"].isna()].copy()\n\n# Create the choropleth map\nplot = (\n    ggplot()\n    + geom_polygon(\n        df_missing, aes(x=\"x\", y=\"y\", group=\"country\"), fill=MISSING_DATA_COLOR, color=INK_SOFT, size=0.6, alpha=0.7\n    )\n    + geom_polygon(\n        df_with_data, aes(x=\"x\", y=\"y\", group=\"country\", fill=\"life_expectancy\"), color=INK_SOFT, size=0.6, alpha=0.95\n    )\n    + geom_text(df_centroids, aes(x=\"x\", y=\"y\", label=\"country\"), size=7, color=INK)\n    + scale_fill_cmap(cmap_name=\"BrBG\", name=\"Life Expectancy\\n(years)\", limits=(77, 85))\n    + coord_fixed(ratio=1.0)\n    + labs(title=\"choropleth-basic · plotnine · anyplot.ai\")\n    + theme(\n        figure_size=(16, 9),\n        plot_title=element_text(size=24, ha=\"center\", color=INK),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_grid=element_blank(),\n        panel_border=element_line(color=INK_SOFT, size=0.3),\n        axis_text=element_blank(),\n        axis_title=element_blank(),\n        axis_ticks=element_blank(),\n        legend_title=element_text(size=16, color=INK),\n        legend_text=element_text(size=14, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_position=\"right\",\n    )\n)\n\n# Save the plot\nplot.save(f\"plot-{THEME}.png\", dpi=300, verbose=False)\n"}