{"spec_id":"scatter-map-geographic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nscatter-map-geographic: Scatter Map with Geographic Points\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 97/100 | Updated: 2026-05-18\n\"\"\"\n\nimport os\n\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_point,\n    geom_polygon,\n    ggplot,\n    labs,\n    scale_color_manual,\n    scale_size_continuous,\n    theme,\n    theme_minimal,\n)\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nBASEMAP_COLOR = \"#E8E3D8\" if THEME == \"light\" else \"#2A2A26\"\nBASEMAP_EDGE = \"#C0B5A8\" if THEME == \"light\" else \"#4A4945\"\nGRID_COLOR = INK if THEME == \"light\" else INK\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\n\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\n\n# Data: Major world cities with population and region\ncities_data = {\n    \"city\": [\n        \"Tokyo\",\n        \"Delhi\",\n        \"Shanghai\",\n        \"Sao Paulo\",\n        \"Mexico City\",\n        \"Cairo\",\n        \"Mumbai\",\n        \"Beijing\",\n        \"Dhaka\",\n        \"Osaka\",\n        \"New York\",\n        \"Karachi\",\n        \"Buenos Aires\",\n        \"Chongqing\",\n        \"Istanbul\",\n        \"Kolkata\",\n        \"Manila\",\n        \"Lagos\",\n        \"Rio de Janeiro\",\n        \"Los Angeles\",\n        \"Moscow\",\n        \"Paris\",\n        \"Bangkok\",\n        \"Seoul\",\n        \"London\",\n        \"Lima\",\n        \"Chicago\",\n        \"Cape Town\",\n        \"Sydney\",\n        \"Toronto\",\n    ],\n    \"latitude\": [\n        35.68,\n        28.61,\n        31.23,\n        -23.55,\n        19.43,\n        30.04,\n        19.08,\n        39.90,\n        23.81,\n        34.69,\n        40.71,\n        24.86,\n        -34.60,\n        29.43,\n        41.01,\n        22.57,\n        14.60,\n        6.52,\n        -22.91,\n        34.05,\n        55.76,\n        48.86,\n        13.76,\n        37.57,\n        51.51,\n        -12.05,\n        41.88,\n        -33.93,\n        -33.87,\n        43.65,\n    ],\n    \"longitude\": [\n        139.69,\n        77.21,\n        121.47,\n        -46.63,\n        -99.13,\n        31.24,\n        72.88,\n        116.41,\n        90.41,\n        135.50,\n        -74.01,\n        67.01,\n        -58.38,\n        106.91,\n        28.98,\n        88.36,\n        120.98,\n        3.38,\n        -43.17,\n        -118.24,\n        37.62,\n        2.35,\n        100.50,\n        127.00,\n        -0.13,\n        -77.04,\n        -87.63,\n        18.42,\n        151.21,\n        -79.38,\n    ],\n    \"population\": [\n        37.4,\n        32.9,\n        29.2,\n        22.4,\n        21.8,\n        21.3,\n        21.0,\n        20.9,\n        22.5,\n        19.1,\n        18.8,\n        16.8,\n        15.4,\n        16.9,\n        15.6,\n        15.1,\n        14.4,\n        15.3,\n        13.5,\n        12.5,\n        12.5,\n        11.0,\n        10.7,\n        9.9,\n        9.5,\n        11.0,\n        8.9,\n        4.8,\n        5.3,\n        6.3,\n    ],\n    \"region\": [\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"S. America\",\n        \"N. America\",\n        \"Africa\",\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"N. America\",\n        \"Asia\",\n        \"S. America\",\n        \"Asia\",\n        \"Europe\",\n        \"Asia\",\n        \"Asia\",\n        \"Africa\",\n        \"S. America\",\n        \"N. America\",\n        \"Europe\",\n        \"Europe\",\n        \"Asia\",\n        \"Asia\",\n        \"Europe\",\n        \"S. America\",\n        \"N. America\",\n        \"Africa\",\n        \"Oceania\",\n        \"N. America\",\n    ],\n}\n\ndf = pd.DataFrame(cities_data)\n\n# Simplified continent outlines for basemap (closed polygons)\ncontinents = []\n\n# North America\nna_lon = [\n    -170,\n    -168,\n    -140,\n    -125,\n    -124,\n    -117,\n    -105,\n    -97,\n    -82,\n    -77,\n    -68,\n    -55,\n    -52,\n    -80,\n    -87,\n    -97,\n    -105,\n    -125,\n    -145,\n    -165,\n    -170,\n]\nna_lat = [60, 65, 70, 55, 48, 33, 25, 26, 25, 35, 45, 48, 45, 27, 30, 20, 22, 50, 60, 55, 60]\nfor i in range(len(na_lon)):\n    continents.append({\"continent\": \"N. America\", \"order\": i, \"lon\": na_lon[i], \"lat\": na_lat[i]})\n\n# South America\nsa_lon = [-80, -68, -60, -50, -35, -40, -50, -55, -68, -72, -75, -80, -82, -80]\nsa_lat = [10, 12, 5, 0, -5, -22, -35, -52, -55, -18, -5, 0, 8, 10]\nfor i in range(len(sa_lon)):\n    continents.append({\"continent\": \"S. America\", \"order\": i, \"lon\": sa_lon[i], \"lat\": sa_lat[i]})\n\n# Europe\neu_lon = [-10, 0, 10, 20, 30, 40, 50, 60, 50, 35, 25, 20, 10, 0, -10, -10]\neu_lat = [35, 37, 36, 35, 35, 40, 45, 55, 70, 70, 70, 65, 60, 50, 40, 35]\nfor i in range(len(eu_lon)):\n    continents.append({\"continent\": \"Europe\", \"order\": i, \"lon\": eu_lon[i], \"lat\": eu_lat[i]})\n\n# Africa\naf_lon = [-17, -5, 10, 35, 50, 52, 43, 35, 30, 15, 0, -17, -17]\naf_lat = [15, 37, 37, 32, 12, 0, -25, -35, -35, -25, 5, 20, 15]\nfor i in range(len(af_lon)):\n    continents.append({\"continent\": \"Africa\", \"order\": i, \"lon\": af_lon[i], \"lat\": af_lat[i]})\n\n# Asia\nas_lon = [60, 80, 100, 120, 140, 145, 140, 130, 105, 100, 80, 60, 45, 30, 25, 30, 35, 50, 60]\nas_lat = [55, 70, 75, 70, 55, 45, 35, 30, 0, 5, 10, 25, 30, 35, 42, 55, 70, 70, 55]\nfor i in range(len(as_lon)):\n    continents.append({\"continent\": \"Asia\", \"order\": i, \"lon\": as_lon[i], \"lat\": as_lat[i]})\n\n# Australia/Oceania\nau_lon = [113, 125, 145, 153, 148, 140, 130, 115, 113]\nau_lat = [-20, -14, -16, -28, -40, -38, -32, -34, -20]\nfor i in range(len(au_lon)):\n    continents.append({\"continent\": \"Oceania\", \"order\": i, \"lon\": au_lon[i], \"lat\": au_lat[i]})\n\ndf_continents = pd.DataFrame(continents)\n\n# Define region colors using Okabe-Ito palette\nregion_colors = {\n    \"Africa\": IMPRINT[0],\n    \"Asia\": IMPRINT[1],\n    \"Europe\": IMPRINT[2],\n    \"N. America\": IMPRINT[3],\n    \"Oceania\": IMPRINT[4],\n    \"S. America\": IMPRINT[5],\n}\n\n# Create the geographic scatter map\nplot = (\n    ggplot()\n    + geom_polygon(\n        aes(x=\"lon\", y=\"lat\", group=\"continent\"),\n        data=df_continents,\n        fill=BASEMAP_COLOR,\n        color=BASEMAP_EDGE,\n        size=0.5,\n        alpha=0.6,\n    )\n    + geom_point(aes(x=\"longitude\", y=\"latitude\", color=\"region\", size=\"population\"), data=df, alpha=0.8, stroke=0.5)\n    + scale_color_manual(values=list(region_colors.values()), name=\"Region\")\n    + scale_size_continuous(range=(4, 20), name=\"Population (M)\")\n    + labs(title=\"scatter-map-geographic · python · plotnine · anyplot.ai\", x=\"Longitude (°)\", y=\"Latitude (°)\")\n    + coord_fixed(ratio=1.0, xlim=(-180, 180), ylim=(-60, 80))\n    + theme_minimal()\n    + theme(\n        figure_size=(16, 9),\n        plot_title=element_text(size=24, color=INK),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        legend_title=element_text(size=18, color=INK),\n        legend_text=element_text(size=14, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT, size=0.3),\n        legend_position=\"right\",\n        panel_grid_major=element_line(color=GRID_COLOR, size=0.3, alpha=0.08),\n        panel_grid_minor=element_blank(),\n        panel_background=element_rect(fill=PAGE_BG, color=None),\n        plot_background=element_rect(fill=PAGE_BG, color=None),\n        panel_border=element_blank(),\n    )\n)\n\n# Save PNG\nplot.save(f\"plot-{THEME}.png\", dpi=300, verbose=False)\n"}