{"spec_id":"map-marker-clustered","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nmap-marker-clustered: Clustered Marker Map\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 86/100 | Updated: 2026-05-23\n\"\"\"\n\nimport os\n\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    element_rect,\n    element_text,\n    geom_point,\n    geom_polygon,\n    geom_text,\n    ggplot,\n    ggsave,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_fill_manual,\n    scale_size,\n    theme,\n    theme_void,\n    xlim,\n    ylim,\n)\n\n\nLetsPlot.setup_html()\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\n# Cluster data: pre-aggregated store locations across US metropolitan areas\n# New England nudged north-east to reduce visual overlap with NYC cluster\ndf_clusters = pd.DataFrame(\n    {\n        \"region\": [\n            \"Los Angeles\",\n            \"San Francisco\",\n            \"Pacific Northwest\",\n            \"Desert Southwest\",\n            \"Chicago\",\n            \"Dallas\",\n            \"Houston\",\n            \"Southeast\",\n            \"South Florida\",\n            \"Washington DC\",\n            \"New York City\",\n            \"New England\",\n        ],\n        \"lon\": [-118.2, -122.5, -122.3, -111.9, -87.6, -96.8, -95.4, -84.4, -80.2, -77.0, -74.0, -70.0],\n        \"lat\": [34.0, 37.8, 47.6, 33.4, 41.9, 32.8, 29.8, 33.7, 26.0, 38.9, 40.7, 43.5],\n        \"count\": [175, 120, 65, 45, 200, 90, 100, 80, 115, 125, 210, 85],\n        \"category\": [\n            \"Retail\",\n            \"Warehouse\",\n            \"Retail\",\n            \"Service Center\",\n            \"Retail\",\n            \"Warehouse\",\n            \"Retail\",\n            \"Service Center\",\n            \"Retail\",\n            \"Warehouse\",\n            \"Retail\",\n            \"Service Center\",\n        ],\n    }\n)\n\n# Imprint palette — canonical order for categorical data\ncolors = {\"Retail\": \"#009E73\", \"Warehouse\": \"#C475FD\", \"Service Center\": \"#AE3030\"}\n\n# Higher-fidelity US continental boundary polygon (66 vertices vs prior 44)\nus_boundary = [\n    # Canadian border west to east\n    (-125, 49),\n    (-120, 49),\n    (-115, 49),\n    (-110, 49),\n    (-105, 49),\n    (-100, 49),\n    (-95, 49),\n    (-90, 47),\n    (-87, 47),\n    # Great Lakes south shoreline\n    (-85, 46),\n    (-82, 46),\n    (-82, 42),\n    (-79, 43),\n    (-76, 44),\n    (-73, 44),\n    # Maine and New England coast\n    (-70, 45),\n    (-67, 45),\n    (-67, 44),\n    (-69, 43.5),\n    (-70, 42.5),\n    (-71, 41.5),\n    (-73, 41),\n    # Mid-Atlantic\n    (-74, 40.5),\n    (-74, 40),\n    (-75, 39),\n    (-75, 38),\n    # Southeast Atlantic coast\n    (-76, 37),\n    (-76, 36),\n    (-76, 35),\n    (-77, 34),\n    (-79, 33.5),\n    (-80, 32),\n    (-81, 31),\n    (-80, 30),\n    (-80, 28),\n    # Florida peninsula\n    (-80, 26),\n    (-81, 25),\n    (-80, 25),\n    # Florida west coast and Gulf of Mexico\n    (-82, 27),\n    (-83, 29),\n    (-84, 30),\n    (-86, 30),\n    (-88, 30),\n    (-89, 29),\n    (-90, 29),\n    (-91, 29),\n    (-94, 29),\n    # Texas Gulf coast\n    (-97, 26),\n    (-97, 27),\n    (-97, 28),\n    (-100, 29),\n    (-104, 29),\n    # Southwest border\n    (-106, 32),\n    (-109, 31),\n    (-111, 31),\n    (-114, 32),\n    # Pacific coast\n    (-117, 32),\n    (-118, 34),\n    (-120, 34),\n    (-122, 37),\n    (-123, 38),\n    (-124, 40),\n    (-124, 43),\n    (-123, 46),\n    (-124, 48),\n    (-125, 49),\n]\ndf_us = pd.DataFrame(us_boundary, columns=[\"x\", \"y\"])\ndf_us[\"group\"] = 0\n\nmap_fill = \"#E0DDD6\" if THEME == \"light\" else \"#2A2A27\"\nmap_border = \"#B0ADA6\" if THEME == \"light\" else \"#4A4A44\"\n\nplot = (\n    ggplot()\n    + geom_polygon(data=df_us, mapping=aes(x=\"x\", y=\"y\", group=\"group\"), fill=map_fill, color=map_border, size=0.5)\n    + geom_point(\n        data=df_clusters,\n        mapping=aes(x=\"lon\", y=\"lat\", size=\"count\", fill=\"category\"),\n        color=INK_SOFT,\n        alpha=0.88,\n        shape=21,\n        stroke=1.5,\n        tooltips=layer_tooltips().title(\"@region\").line(\"@count locations\").line(\"Type|@category\"),\n    )\n    + geom_text(\n        data=df_clusters, mapping=aes(x=\"lon\", y=\"lat\", label=\"count\"), color=\"#FFFFFF\", size=10, fontface=\"bold\"\n    )\n    + scale_fill_manual(values=colors, name=\"Store Type\")\n    + scale_size(range=[6, 20], name=\"Locations\", breaks=[50, 100, 150, 200])\n    + labs(\n        title=\"map-marker-clustered · python · letsplot · anyplot.ai\",\n        caption=\"Store locations clustered by metropolitan area · 1,410 total\",\n    )\n    + theme_void()\n    + theme(\n        plot_title=element_text(size=16, hjust=0.5, face=\"bold\", color=INK),\n        plot_caption=element_text(size=10, hjust=0.5, color=INK_SOFT),\n        legend_title=element_text(size=12, color=INK),\n        legend_text=element_text(size=10, color=INK_SOFT),\n        legend_position=\"right\",\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n    )\n    + ggsize(800, 450)\n    + xlim(-130, -65)\n    + ylim(23, 52)\n)\n\nggsave(plot, f\"plot-{THEME}.png\", scale=4, path=\".\")\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}