{"spec_id":"map-projections","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nmap-projections: World Map with Different Projections\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 84/100 | Created: 2026-05-23\n\"\"\"\n\nimport os\nimport sys\n\n\nsys.path.pop(0)\nimport altair as alt\nfrom PIL import Image\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\"\n\nBRAND = \"#009E73\"\n\nWORLD_URL = \"https://cdn.jsdelivr.net/npm/vega-datasets@1.31.1/data/world-110m.json\"\n\nMAIN_TITLE = \"map-projections · python · altair · anyplot.ai\"\n\n\ndef make_panel(proj_type, label, subtitle, w, h):\n    sphere = alt.Chart(alt.sphere()).mark_geoshape(\n        fill=ELEVATED_BG, stroke=INK_SOFT, strokeWidth=0.4, strokeOpacity=0.6\n    )\n    graticule = alt.Chart(alt.graticule(step=[30, 30])).mark_geoshape(\n        filled=False, stroke=INK_SOFT, strokeWidth=0.3, strokeOpacity=0.35\n    )\n    countries = alt.Chart(alt.topo_feature(WORLD_URL, \"countries\")).mark_geoshape(\n        fill=BRAND, stroke=PAGE_BG, strokeWidth=0.5, fillOpacity=0.88\n    )\n    return (\n        (sphere + graticule + countries)\n        .project(type=proj_type)\n        .properties(\n            width=w,\n            height=h,\n            title=alt.Title(\n                text=label,\n                subtitle=subtitle,\n                fontSize=12,\n                subtitleFontSize=9,\n                color=INK,\n                subtitleColor=INK_SOFT,\n                anchor=\"middle\",\n            ),\n        )\n    )\n\n\n# 4 projections in a 2×2 grid\n# Mercator clips naturally at height=145 — avoids infinite polar distortion\nmap_mercator = make_panel(\"mercator\", \"Mercator\", \"conformal · cylindrical · distorts area near poles\", 240, 110)\nmap_natural = make_panel(\"naturalEarth1\", \"Natural Earth\", \"compromise · minimises overall distortion\", 240, 130)\nmap_equal_earth = make_panel(\"equalEarth\", \"Equal Earth\", \"equal-area · preserves relative country sizes\", 240, 120)\nmap_orthographic = make_panel(\"orthographic\", \"Orthographic\", \"azimuthal · perspective view from space\", 195, 185)\n\nrow1 = alt.hconcat(map_mercator, map_natural, spacing=20)\nrow2 = alt.hconcat(map_equal_earth, map_orthographic, spacing=20)\n\nchart = (\n    alt.vconcat(row1, row2, spacing=18)\n    .properties(background=PAGE_BG, title=alt.Title(text=MAIN_TITLE, fontSize=16, color=INK, anchor=\"middle\"))\n    .configure_view(stroke=None)\n)\n\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\nTW, TH = 3200, 1800\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\nchart.save(f\"plot-{THEME}.html\")\n"}