{"spec_id":"map-route-path","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nmap-route-path: Route Path Map\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Created: 2026-05-21\n\"\"\"\n\nimport os\nimport sys\n\n\nsys.path.pop(0)  # prevent local altair.py from shadowing the library\nimport altair as alt\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\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\"\nMAP_FILL = \"#DEDAD4\" if THEME == \"light\" else \"#2C2C28\"\nMAP_STROKE = \"#B0AAA0\" if THEME == \"light\" else \"#4A4A42\"\n\n# Data — Route 66: Chicago → Los Angeles (8 segments, ~160 synthetic waypoints)\nnp.random.seed(42)\n\ncity_coords = [\n    (41.85, -87.65),  # Chicago, IL\n    (39.80, -89.65),  # Springfield, IL\n    (38.63, -90.20),  # St. Louis, MO\n    (37.08, -94.52),  # Joplin, MO\n    (35.47, -97.52),  # Oklahoma City, OK\n    (35.22, -101.83),  # Amarillo, TX\n    (35.08, -106.65),  # Albuquerque, NM\n    (35.20, -111.65),  # Flagstaff, AZ\n    (34.05, -118.25),  # Los Angeles, CA\n]\ncity_elevations = [180, 165, 130, 290, 365, 1100, 1510, 2100, 95]\n\nrows = []\nseq = 0\nfor i in range(len(city_coords) - 1):\n    lat1, lon1 = city_coords[i]\n    lat2, lon2 = city_coords[i + 1]\n    n = 20\n    t_vals = np.linspace(0, 1, n + 1)[:-1]\n    lats = lat1 + (lat2 - lat1) * t_vals + np.random.normal(0, 0.07, n)\n    lons = lon1 + (lon2 - lon1) * t_vals + np.random.normal(0, 0.07, n)\n    for j in range(n):\n        rows.append({\"lat\": lats[j], \"lon\": lons[j], \"sequence\": seq})\n        seq += 1\nrows.append({\"lat\": city_coords[-1][0], \"lon\": city_coords[-1][1], \"sequence\": seq})\ndf = pd.DataFrame(rows)\n\ncity_s = np.linspace(0, 1, len(city_coords))\nroute_s = df[\"sequence\"].values / df[\"sequence\"].max()\ndf[\"elevation_m\"] = np.interp(route_s, city_s, city_elevations) + np.random.normal(0, 45, len(df))\n\nstart_df = df.iloc[[0]].copy()\nstart_df[\"label\"] = \"Start: Chicago, IL\"\nend_df = df.iloc[[-1]].copy()\nend_df[\"label\"] = \"End: Los Angeles, CA\"\ndot_df = df.iloc[::3].reset_index(drop=True)\n\n# City label DataFrames (separate layers needed for different per-label alignment)\nchicago_ldf = pd.DataFrame([{\"lon\": city_coords[0][1], \"lat\": city_coords[0][0], \"label\": \"Chicago\"}])\nla_ldf = pd.DataFrame([{\"lon\": city_coords[-1][1], \"lat\": city_coords[-1][0], \"label\": \"Los Angeles\"}])\nflagstaff_ldf = pd.DataFrame([{\"lon\": city_coords[7][1], \"lat\": city_coords[7][0], \"label\": \"▲ Flagstaff 2100m\"}])\n\ntitle_str = \"Route 66 Road Trip · map-route-path · python · altair · anyplot.ai\"\n\n# Basemap: US states (CDN topojson, no local package required)\nus_url = \"https://cdn.jsdelivr.net/npm/vega-datasets@2/data/us-10m.json\"\nstates = alt.topo_feature(us_url, \"states\")\n\n# Map layers\nbackground = (\n    alt.Chart(states)\n    .mark_geoshape(fill=MAP_FILL, stroke=MAP_STROKE, strokeWidth=0.6)\n    .project(type=\"albersUsa\")\n    .properties(width=620, height=320)\n)\n\nroute_line = (\n    alt.Chart(df)\n    .mark_line(strokeWidth=3.5, color=\"#009E73\", strokeCap=\"round\")\n    .encode(\n        longitude=\"lon:Q\",\n        latitude=\"lat:Q\",\n        order=\"sequence:O\",\n        tooltip=[\n            alt.Tooltip(\"lat:Q\", title=\"Latitude\", format=\".2f\"),\n            alt.Tooltip(\"lon:Q\", title=\"Longitude\", format=\".2f\"),\n            alt.Tooltip(\"elevation_m:Q\", title=\"Elevation (m)\", format=\".0f\"),\n        ],\n    )\n    .project(type=\"albersUsa\")\n)\n\nelevation_dots = (\n    alt.Chart(dot_df)\n    .mark_circle(size=55, opacity=0.9)\n    .encode(\n        longitude=\"lon:Q\",\n        latitude=\"lat:Q\",\n        color=alt.Color(\n            \"elevation_m:Q\",\n            scale=alt.Scale(scheme=\"viridis\"),\n            legend=alt.Legend(\n                title=\"Elevation (m)\",\n                titleFontSize=12,\n                labelFontSize=10,\n                gradientLength=180,\n                gradientThickness=14,\n                orient=\"bottom-right\",\n                offset=10,\n            ),\n        ),\n        order=\"sequence:O\",\n        tooltip=[alt.Tooltip(\"elevation_m:Q\", title=\"Elevation (m)\", format=\".0f\")],\n    )\n    .project(type=\"albersUsa\")\n)\n\nstart_marker = (\n    alt.Chart(start_df)\n    .mark_point(shape=\"circle\", size=320, filled=True, color=\"#009E73\", stroke=\"white\", strokeWidth=2.5)\n    .encode(longitude=\"lon:Q\", latitude=\"lat:Q\", tooltip=\"label:N\")\n    .project(type=\"albersUsa\")\n)\n\nend_marker = (\n    alt.Chart(end_df)\n    .mark_point(shape=\"square\", size=320, filled=True, color=\"#C475FD\", stroke=\"white\", strokeWidth=2.5)\n    .encode(longitude=\"lon:Q\", latitude=\"lat:Q\", tooltip=\"label:N\")\n    .project(type=\"albersUsa\")\n)\n\n# Chicago: center-aligned above the start marker\nchicago_label = (\n    alt.Chart(chicago_ldf)\n    .mark_text(fontSize=10, fontWeight=\"bold\", dy=-18, baseline=\"bottom\", align=\"center\")\n    .encode(longitude=\"lon:Q\", latitude=\"lat:Q\", text=\"label:N\", color=alt.value(INK))\n    .project(type=\"albersUsa\")\n)\n\n# Los Angeles: right-aligned (text extends west, clear of Flagstaff overlap)\nla_label = (\n    alt.Chart(la_ldf)\n    .mark_text(fontSize=10, fontWeight=\"bold\", dy=-18, baseline=\"bottom\", align=\"right\")\n    .encode(longitude=\"lon:Q\", latitude=\"lat:Q\", text=\"label:N\", color=alt.value(INK))\n    .project(type=\"albersUsa\")\n)\n\n# Flagstaff elevation peak: left-aligned + higher offset, extends east away from LA label\nflagstaff_label = (\n    alt.Chart(flagstaff_ldf)\n    .mark_text(fontSize=9, fontWeight=\"bold\", dy=-32, baseline=\"bottom\", align=\"left\", dx=6)\n    .encode(longitude=\"lon:Q\", latitude=\"lat:Q\", text=\"label:N\", color=alt.value(INK))\n    .project(type=\"albersUsa\")\n)\n\nchart = (\n    (background + route_line + elevation_dots + start_marker + end_marker + chicago_label + la_label + flagstaff_label)\n    .properties(background=PAGE_BG, title=alt.Title(text=title_str, fontSize=14, anchor=\"start\", color=INK, offset=8))\n    .configure_view(fill=PAGE_BG, strokeWidth=0)\n    .configure_title(color=INK)\n    .configure_legend(fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK)\n)\n\n# Save PNG + HTML\nTW, TH = 3200, 1800\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\nchart.save(f\"plot-{THEME}.html\")\n\n# Canvas check: pad to target, raise on overshoot\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n"}