{"spec_id":"bubble-map-geographic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nbubble-map-geographic: Bubble Map with Sized Geographic Markers\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 81/100 | Updated: 2026-05-18\n\"\"\"\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Simplified world coastline polygons (major continents outline)\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: World cities with populations (millions)\nnp.random.seed(42)\n\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        \"Istanbul\",\n        \"Kolkata\",\n        \"Manila\",\n        \"Lagos\",\n        \"Rio de Janeiro\",\n        \"Guangzhou\",\n        \"Los Angeles\",\n        \"Moscow\",\n        \"Paris\",\n        \"Bangkok\",\n        \"London\",\n        \"Lima\",\n        \"Seoul\",\n        \"Sydney\",\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        41.01,\n        22.57,\n        14.60,\n        6.52,\n        -22.91,\n        23.13,\n        34.05,\n        55.76,\n        48.86,\n        13.76,\n        51.51,\n        -12.05,\n        37.57,\n        -33.87,\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        28.98,\n        88.36,\n        120.98,\n        3.38,\n        -43.17,\n        113.26,\n        -118.24,\n        37.62,\n        2.35,\n        100.50,\n        -0.13,\n        -77.04,\n        127.00,\n        151.21,\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.5,\n        15.4,\n        14.9,\n        14.4,\n        14.4,\n        13.6,\n        13.5,\n        12.5,\n        12.5,\n        11.1,\n        10.7,\n        9.5,\n        10.9,\n        9.8,\n        5.4,\n    ],\n    \"continent\": [\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"South America\",\n        \"North America\",\n        \"Africa\",\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"Asia\",\n        \"North America\",\n        \"Asia\",\n        \"South America\",\n        \"Europe\",\n        \"Asia\",\n        \"Asia\",\n        \"Africa\",\n        \"South America\",\n        \"Asia\",\n        \"North America\",\n        \"Europe\",\n        \"Europe\",\n        \"Asia\",\n        \"Europe\",\n        \"South America\",\n        \"Asia\",\n        \"Oceania\",\n    ],\n}\n\ndf = pd.DataFrame(cities_data)\n\n# Scale bubble sizes: area proportional to population using sqrt scaling\n# Bubble map emphasizes size encoding - use larger range than scatter\nmin_size = 120\nmax_size = 2200\ndf[\"bubble_size\"] = min_size + (max_size - min_size) * (np.sqrt(df[\"population\"]) / np.sqrt(df[\"population\"].max()))\n\n# Set seaborn theme\nsns.set_theme(style=\"whitegrid\", context=\"talk\", font_scale=1.1)\n\n# Create figure\nfig, ax = plt.subplots(figsize=(16, 9))\n\n# Set map extent\nax.set_xlim(-180, 180)\nax.set_ylim(-70, 85)\nax.set_aspect(\"equal\")\n\n# Draw simplified coastlines as background\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=\"#e8e8e8\", edgecolor=\"#b0b0b0\", linewidth=1, alpha=0.8, zorder=1)\n\n# Ocean background\nax.set_facecolor(\"#d4e8f7\")\n\n# Color palette for continents\ncontinent_palette = {\n    \"Asia\": \"#306998\",\n    \"Europe\": \"#FFD43B\",\n    \"North America\": \"#E07B53\",\n    \"South America\": \"#5AAE61\",\n    \"Africa\": \"#9D6AB8\",\n    \"Oceania\": \"#2DB5AE\",\n}\n\n# Plot bubbles using seaborn scatterplot\n# Use size parameter with explicit sizes tuple for bubble encoding\nsns.scatterplot(\n    data=df,\n    x=\"longitude\",\n    y=\"latitude\",\n    hue=\"continent\",\n    size=\"population\",\n    sizes=(min_size, max_size),\n    palette=continent_palette,\n    alpha=0.6,\n    edgecolor=\"white\",\n    linewidth=2,\n    ax=ax,\n    zorder=3,\n    legend=\"full\",\n)\n\n# Customize legends - separate continent and size legends\nhandles, labels = ax.get_legend_handles_labels()\n\n# Find indices for continent legend (skip size entries)\ncontinent_indices = [i for i, label in enumerate(labels) if label in continent_palette]\ncontinent_handles = [handles[i] for i in continent_indices]\ncontinent_labels = [labels[i] for i in continent_indices]\n\n# Continent legend\nlegend1 = ax.legend(\n    continent_handles,\n    continent_labels,\n    loc=\"lower left\",\n    fontsize=14,\n    title=\"Continent\",\n    title_fontsize=16,\n    framealpha=0.95,\n    edgecolor=\"#cccccc\",\n)\nax.add_artist(legend1)\n\n# Size legend showing population scale\nsize_legend_pops = [5, 15, 30]\nsize_legend_elements = []\nfor pop in size_legend_pops:\n    size = min_size + (max_size - min_size) * (np.sqrt(pop) / np.sqrt(df[\"population\"].max()))\n    elem = plt.scatter([], [], s=size, c=\"gray\", alpha=0.6, edgecolor=\"white\", linewidth=1.5)\n    size_legend_elements.append(elem)\n\nsize_legend = ax.legend(\n    handles=size_legend_elements,\n    labels=[f\"{p}M\" for p in size_legend_pops],\n    loc=\"lower right\",\n    fontsize=14,\n    title=\"Population\",\n    title_fontsize=16,\n    framealpha=0.95,\n    edgecolor=\"#cccccc\",\n    labelspacing=1.8,\n)\n\n# Labels and styling\nax.set_xlabel(\"Longitude (°)\", fontsize=20)\nax.set_ylabel(\"Latitude (°)\", fontsize=20)\nax.set_title(\n    \"World Major City Populations · bubble-map-geographic · seaborn · pyplots.ai\",\n    fontsize=24,\n    fontweight=\"bold\",\n    pad=20,\n)\nax.tick_params(axis=\"both\", labelsize=16)\n\n# Subtle grid\nax.grid(True, alpha=0.3, linestyle=\"--\", color=\"#888888\")\nax.set_axisbelow(True)\n\nplt.tight_layout()\nplt.savefig(\"plot.png\", dpi=300, bbox_inches=\"tight\")\n"}