{"spec_id":"map-tile-background","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nmap-tile-background: Map with Tile Background\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 82/100 | Updated: 2026-05-27\n\"\"\"\n\nimport os\nimport sys\n\nimport numpy as np\nimport pandas as pd\n\n\n# Work around naming conflict with plotnine.py script and plotnine package\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nif script_dir in sys.path:\n    sys.path.remove(script_dir)\nif \"\" in sys.path:\n    sys.path.remove(\"\")\nif \".\" in sys.path:\n    sys.path.remove(\".\")\n\nfrom plotnine import (\n    aes,\n    annotate,\n    coord_fixed,\n    element_blank,\n    element_rect,\n    element_text,\n    geom_label,\n    geom_point,\n    geom_polygon,\n    geom_rect,\n    ggplot,\n    labs,\n    scale_color_manual,\n    scale_fill_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\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\"]\n\nnp.random.seed(42)\n\n# San Francisco Bay Area landmarks with visitor counts (thousands per year)\nlandmarks_data = {\n    \"name\": [\n        \"Golden Gate Bridge\",\n        \"Alcatraz Island\",\n        \"Fisherman's Wharf\",\n        \"Pier 39\",\n        \"Cable Cars\",\n        \"Chinatown\",\n        \"Union Square\",\n        \"Ferry Building\",\n        \"Palace of Fine Arts\",\n        \"Coit Tower\",\n        \"AT&T Park\",\n        \"Exploratorium\",\n        \"de Young Museum\",\n        \"California Academy\",\n        \"Lombard Street\",\n    ],\n    \"lat\": [\n        37.8199,\n        37.8267,\n        37.8080,\n        37.8087,\n        37.7873,\n        37.7941,\n        37.7879,\n        37.7955,\n        37.8020,\n        37.8024,\n        37.7786,\n        37.8016,\n        37.7714,\n        37.7699,\n        37.8021,\n    ],\n    \"lon\": [\n        -122.4783,\n        -122.4230,\n        -122.4177,\n        -122.4098,\n        -122.4119,\n        -122.4070,\n        -122.4075,\n        -122.3935,\n        -122.4486,\n        -122.4058,\n        -122.3893,\n        -122.3976,\n        -122.4687,\n        -122.4663,\n        -122.4187,\n    ],\n    \"visitors\": [10500, 1700, 12000, 10000, 7000, 2000, 15000, 6000, 2000, 500, 3500, 1000, 1200, 2500, 2000],\n    \"category\": [\n        \"Landmark\",\n        \"Historic\",\n        \"Tourism\",\n        \"Tourism\",\n        \"Transport\",\n        \"Cultural\",\n        \"Shopping\",\n        \"Tourism\",\n        \"Landmark\",\n        \"Landmark\",\n        \"Sports\",\n        \"Museum\",\n        \"Museum\",\n        \"Museum\",\n        \"Landmark\",\n    ],\n}\n\ndf = pd.DataFrame(landmarks_data)\n\n# Simulated tile-style background using grid rectangles\nlon_min, lon_max = -122.52, -122.36\nlat_min, lat_max = 37.755, 37.84\n\nn_tiles_x = 10\nn_tiles_y = 8\ntile_width = (lon_max - lon_min) / n_tiles_x\ntile_height = (lat_max - lat_min) / n_tiles_y\n\n# Theme-adaptive terrain colors\nwater_color = \"#B8D4E8\" if THEME == \"light\" else \"#1D2E3A\"\nland_color = \"#E8E4D8\" if THEME == \"light\" else \"#2B2820\"\ncoast_color = \"#8A7A6B\" if THEME == \"light\" else \"#7A7268\"\n\ntiles = []\nfor i in range(n_tiles_x):\n    for j in range(n_tiles_y):\n        x_center = lon_min + tile_width * (i + 0.5)\n        y_center = lat_min + tile_height * (j + 0.5)\n\n        is_water = (\n            (x_center > -122.39 and y_center < 37.79)\n            or (x_center > -122.44 and y_center > 37.825)\n            or (x_center > -122.37)\n        )\n\n        tiles.append(\n            {\n                \"xmin\": lon_min + tile_width * i,\n                \"xmax\": lon_min + tile_width * (i + 1),\n                \"ymin\": lat_min + tile_height * j,\n                \"ymax\": lat_min + tile_height * (j + 1),\n                \"terrain\": \"water\" if is_water else \"land\",\n            }\n        )\n\ndf_tiles = pd.DataFrame(tiles)\n\n# Coastline polygon (San Francisco peninsula outline)\ncoast_coords = [\n    (-122.52, 37.755),\n    (-122.48, 37.755),\n    (-122.42, 37.76),\n    (-122.39, 37.77),\n    (-122.37, 37.785),\n    (-122.36, 37.80),\n    (-122.38, 37.815),\n    (-122.42, 37.82),\n    (-122.46, 37.825),\n    (-122.50, 37.82),\n    (-122.52, 37.80),\n    (-122.52, 37.755),\n]\n\ncoastline = [{\"region\": \"sf\", \"order\": i, \"lon\": c[0], \"lat\": c[1]} for i, c in enumerate(coast_coords)]\ndf_coast = pd.DataFrame(coastline)\n\n# Imprint palette assigned alphabetically by category\ncategories_sorted = sorted(df[\"category\"].unique())\ncategory_colors = {cat: IMPRINT_PALETTE[i] for i, cat in enumerate(categories_sorted)}\n\n# Labels for top 3 most-visited landmarks (well-separated geographically)\ntop3 = df.nlargest(3, \"visitors\")  # Union Square, Fisherman's Wharf, Golden Gate Bridge\nlabel_positions = {\n    \"Union Square\": {\"nudge_x\": 0.025, \"nudge_y\": 0.012},\n    \"Fisherman's Wharf\": {\"nudge_x\": -0.035, \"nudge_y\": 0.014},\n    \"Golden Gate Bridge\": {\"nudge_x\": 0.015, \"nudge_y\": 0.014},\n}\n\nlabel_records = []\nfor _, row in top3.iterrows():\n    pos = label_positions.get(row[\"name\"], {\"nudge_x\": 0, \"nudge_y\": 0.012})\n    label_records.append({\"name\": row[\"name\"], \"lon\": row[\"lon\"] + pos[\"nudge_x\"], \"lat\": row[\"lat\"] + pos[\"nudge_y\"]})\nlabel_df = pd.DataFrame(label_records)\n\ntitle = \"map-tile-background · python · plotnine · anyplot.ai\"\n\nplot = (\n    ggplot()\n    + geom_rect(\n        aes(xmin=\"xmin\", xmax=\"xmax\", ymin=\"ymin\", ymax=\"ymax\", fill=\"terrain\"),\n        data=df_tiles,\n        color=INK_MUTED,\n        size=0.05,\n        alpha=0.85,\n    )\n    + scale_fill_manual(values={\"water\": water_color, \"land\": land_color}, guide=None)\n    + geom_polygon(aes(x=\"lon\", y=\"lat\", group=\"region\"), data=df_coast, fill=\"none\", color=coast_color, size=0.8)\n    + geom_point(aes(x=\"lon\", y=\"lat\", color=\"category\", size=\"visitors\"), data=df, alpha=0.88, stroke=0.4)\n    + scale_size_continuous(range=(2, 10), name=\"Visitors\\n(K/yr)\")\n    + scale_color_manual(values=category_colors, name=\"Category\")\n    + geom_label(\n        aes(x=\"lon\", y=\"lat\", label=\"name\"),\n        data=label_df,\n        size=3.5,\n        alpha=0.92,\n        fill=ELEVATED_BG,\n        color=INK,\n        label_padding=0.2,\n    )\n    + annotate(\n        \"text\",\n        x=lon_max - 0.003,\n        y=lat_min + 0.003,\n        label=\"Simulated tiles · SF landmarks\",\n        size=2.5,\n        ha=\"right\",\n        va=\"bottom\",\n        color=INK_MUTED,\n    )\n    + coord_fixed(ratio=1.06, xlim=(lon_min, lon_max), ylim=(lat_min, lat_max))\n    + labs(title=title, x=\"Longitude (°)\", y=\"Latitude (°)\")\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major=element_blank(),\n        panel_grid_minor=element_blank(),\n        panel_border=element_rect(color=INK_SOFT, fill=None),\n        plot_title=element_text(size=12, weight=\"bold\", ha=\"center\", color=INK),\n        axis_title=element_text(size=10, color=INK),\n        axis_text=element_text(size=8, color=INK_SOFT),\n        legend_title=element_text(size=9, color=INK),\n        legend_text=element_text(size=8, color=INK_SOFT),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_position=\"right\",\n        legend_key_size=10,\n        plot_margin=0.01,\n    )\n)\n\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}