{"spec_id":"scatter-map-geographic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nscatter-map-geographic: Scatter Map with Geographic Points\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 94/100 | Updated: 2026-05-18\n\"\"\"\n\nimport os\nimport sys\n\n\n# Work around matplotlib.py shadowing (remove script dir from path)\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != script_dir]\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens\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\n# Okabe-Ito palette (first series always brand green)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\n\n# Simplified world coastline polygons\nWORLD_COASTLINES = [\n    # North America\n    [\n        (-168, 66),\n        (-141, 70),\n        (-130, 70),\n        (-120, 60),\n        (-125, 50),\n        (-125, 40),\n        (-117, 33),\n        (-105, 25),\n        (-97, 26),\n        (-82, 25),\n        (-81, 30),\n        (-75, 35),\n        (-70, 42),\n        (-67, 45),\n        (-60, 47),\n        (-55, 52),\n        (-60, 60),\n        (-65, 68),\n        (-80, 70),\n        (-100, 73),\n        (-120, 75),\n        (-145, 72),\n        (-168, 66),\n    ],\n    # South America\n    [\n        (-82, 10),\n        (-77, 0),\n        (-80, -5),\n        (-70, -15),\n        (-60, -5),\n        (-50, 0),\n        (-35, -5),\n        (-40, -23),\n        (-55, -35),\n        (-68, -55),\n        (-75, -50),\n        (-75, -40),\n        (-70, -20),\n        (-80, -5),\n        (-82, 10),\n    ],\n    # Europe\n    [\n        (-10, 36),\n        (-10, 45),\n        (-5, 48),\n        (0, 52),\n        (5, 55),\n        (10, 58),\n        (20, 60),\n        (28, 70),\n        (35, 70),\n        (30, 60),\n        (25, 55),\n        (20, 50),\n        (15, 45),\n        (20, 40),\n        (25, 35),\n        (35, 35),\n        (28, 42),\n        (20, 38),\n        (10, 38),\n        (-10, 36),\n    ],\n    # Africa\n    [\n        (-17, 15),\n        (-17, 28),\n        (-5, 36),\n        (10, 38),\n        (20, 33),\n        (35, 30),\n        (45, 12),\n        (52, 12),\n        (45, 0),\n        (42, -10),\n        (35, -25),\n        (25, -34),\n        (18, -35),\n        (12, -20),\n        (15, -5),\n        (5, 5),\n        (-10, 5),\n        (-17, 15),\n    ],\n    # Asia\n    [\n        (35, 30),\n        (45, 42),\n        (52, 45),\n        (70, 42),\n        (80, 30),\n        (75, 15),\n        (90, 22),\n        (100, 15),\n        (105, 22),\n        (110, 5),\n        (120, 25),\n        (130, 35),\n        (140, 45),\n        (145, 55),\n        (135, 70),\n        (100, 78),\n        (70, 75),\n        (50, 70),\n        (30, 70),\n        (35, 50),\n        (45, 45),\n        (35, 30),\n    ],\n    # Australia\n    [\n        (113, -22),\n        (120, -18),\n        (135, -12),\n        (145, -15),\n        (152, -25),\n        (150, -38),\n        (140, -38),\n        (130, -33),\n        (115, -35),\n        (113, -22),\n    ],\n]\n\n# Data: Major world cities with population\ncities_data = {\n    \"city\": [\n        \"Tokyo\",\n        \"New York\",\n        \"London\",\n        \"Sydney\",\n        \"Paris\",\n        \"Dubai\",\n        \"Singapore\",\n        \"Mumbai\",\n        \"Cairo\",\n        \"São Paulo\",\n        \"Toronto\",\n        \"Shanghai\",\n        \"Moscow\",\n        \"Seoul\",\n        \"Los Angeles\",\n        \"Berlin\",\n        \"Bangkok\",\n        \"Jakarta\",\n        \"Cape Town\",\n        \"Buenos Aires\",\n        \"Mexico City\",\n        \"Istanbul\",\n        \"Lagos\",\n        \"Chicago\",\n        \"Hong Kong\",\n    ],\n    \"latitude\": [\n        35.7,\n        40.7,\n        51.5,\n        -33.9,\n        48.9,\n        25.2,\n        1.3,\n        19.1,\n        30.0,\n        -23.6,\n        43.7,\n        31.2,\n        55.8,\n        37.6,\n        34.1,\n        52.5,\n        13.8,\n        -6.2,\n        -33.9,\n        -34.6,\n        19.4,\n        41.0,\n        6.5,\n        41.9,\n        22.3,\n    ],\n    \"longitude\": [\n        139.7,\n        -74.0,\n        -0.1,\n        151.2,\n        2.4,\n        55.3,\n        103.8,\n        72.9,\n        31.2,\n        -46.6,\n        -79.4,\n        121.5,\n        37.6,\n        127.0,\n        -118.2,\n        13.4,\n        100.5,\n        106.8,\n        18.4,\n        -58.4,\n        -99.1,\n        29.0,\n        3.4,\n        -87.6,\n        114.2,\n    ],\n    \"population\": [\n        37.4,\n        18.8,\n        9.5,\n        5.3,\n        11.0,\n        3.4,\n        5.7,\n        21.0,\n        20.9,\n        22.4,\n        6.3,\n        27.8,\n        12.5,\n        9.8,\n        12.5,\n        3.7,\n        10.7,\n        10.6,\n        4.6,\n        15.4,\n        21.8,\n        15.5,\n        15.4,\n        8.9,\n        7.5,\n    ],\n    \"region\": [\n        \"Asia\",\n        \"North America\",\n        \"Europe\",\n        \"Oceania\",\n        \"Europe\",\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"Africa\",\n        \"South America\",\n        \"North America\",\n        \"Asia\",\n        \"Europe\",\n        \"Asia\",\n        \"North America\",\n        \"Europe\",\n        \"Asia\",\n        \"Asia\",\n        \"Africa\",\n        \"South America\",\n        \"North America\",\n        \"Europe\",\n        \"Africa\",\n        \"North America\",\n        \"Asia\",\n    ],\n}\n\ndf = pd.DataFrame(cities_data)\n\n# Create figure with seaborn styling\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.10,\n    },\n)\n\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\n\n# Set map extent\nax.set_xlim(-180, 180)\nax.set_ylim(-75, 85)\nax.set_aspect(\"equal\")\n\n# Land background color (theme-adaptive)\nland_color = \"#E8E8E0\" if THEME == \"light\" else \"#2A2A26\"\nland_edge = \"#A8A7A0\" if THEME == \"light\" else \"#505050\"\n\n# Draw coastlines\nfor coastline in WORLD_COASTLINES:\n    if len(coastline) > 2:\n        lons = [p[0] for p in coastline]\n        lats = [p[1] for p in coastline]\n        ax.fill(lons, lats, color=land_color, edgecolor=land_edge, linewidth=0.8, alpha=0.7, zorder=1)\n\n# Create color palette: Asia (position 1, green), Europe (2, orange), Africa (3, blue), Americas (4, purple), Oceania (5, sky blue)\nregion_colors = {\n    \"Asia\": IMPRINT[0],  # #009E73 (brand green)\n    \"Europe\": IMPRINT[1],  # #C475FD (orange)\n    \"Africa\": IMPRINT[2],  # #4467A3 (blue)\n    \"South America\": IMPRINT[3],  # #BD8233 (reddish purple)\n    \"North America\": IMPRINT[1],  # #C475FD (orange, same as Europe for Americas)\n    \"Oceania\": IMPRINT[5],  # #2ABCCD (sky blue)\n}\n\n# Add region color to dataframe\ndf[\"color\"] = df[\"region\"].map(region_colors)\n\n# Scale population for marker sizes\nmin_pop, max_pop = df[\"population\"].min(), df[\"population\"].max()\ndf[\"marker_size\"] = 100 + (df[\"population\"] - min_pop) / (max_pop - min_pop) * 600\n\n# Plot points with seaborn\nsns.scatterplot(\n    data=df,\n    x=\"longitude\",\n    y=\"latitude\",\n    hue=\"region\",\n    size=\"population\",\n    sizes=(100, 700),\n    palette=region_colors,\n    alpha=0.75,\n    edgecolor=PAGE_BG,\n    linewidth=1.2,\n    ax=ax,\n    zorder=3,\n)\n\n# Customize legend - only show region legend\nhandles, labels = ax.get_legend_handles_labels()\n# Get region legend items (skip title and size legend)\nlegend1 = ax.legend(\n    handles[0:6],\n    labels[0:6],\n    loc=\"lower left\",\n    fontsize=16,\n    title=\"Region\",\n    title_fontsize=18,\n    framealpha=0.9,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n)\nax.add_artist(legend1)\n\n# Add size legend\nsize_legend_elements = [\n    plt.scatter([], [], s=100, c=INK_SOFT, alpha=0.6, label=\"5M people\"),\n    plt.scatter([], [], s=350, c=INK_SOFT, alpha=0.6, label=\"20M people\"),\n    plt.scatter([], [], s=700, c=INK_SOFT, alpha=0.6, label=\"35M+ people\"),\n]\nsize_legend = ax.legend(\n    handles=size_legend_elements,\n    loc=\"lower right\",\n    fontsize=14,\n    title=\"Population\",\n    title_fontsize=16,\n    framealpha=0.9,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n)\n\n# Labels and title\nax.set_xlabel(\"Longitude (°)\", fontsize=20, color=INK)\nax.set_ylabel(\"Latitude (°)\", fontsize=20, color=INK)\nax.set_title(\n    \"scatter-map-geographic · python · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK, pad=20\n)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Grid styling\nax.grid(True, alpha=0.10, linestyle=\"-\", linewidth=0.6, color=INK_SOFT)\nax.set_axisbelow(True)\n\n# Spine styling\nfor spine in [\"top\", \"right\"]:\n    ax.spines[spine].set_visible(False)\nfor spine in [\"left\", \"bottom\"]:\n    ax.spines[spine].set_color(INK_SOFT)\n\nplt.tight_layout()\noutput_path = os.path.join(os.path.dirname(__file__), f\"plot-{THEME}.png\")\nplt.savefig(output_path, dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}