{"spec_id":"map-route-path","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nmap-route-path: Route Path Map\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 85/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.collections import LineCollection\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\"\n\n# Okabe-Ito positions for start/end markers\nSTART_COLOR = \"#009E73\"  # position 1 — green\nEND_COLOR = \"#C475FD\"  # position 2 — vermillion\n\n# Data: Simulated hiking trail GPS track (San Francisco coastal path)\nnp.random.seed(42)\nn_points = 150\n\nt = np.linspace(0, 4 * np.pi, n_points)\nlon = -122.4 + 0.03 * t / (4 * np.pi) + 0.008 * np.sin(2 * t) + np.cumsum(np.random.randn(n_points) * 0.0003)\nlat = 37.75 + 0.025 * np.sin(t) + 0.015 * np.cos(1.5 * t) + np.cumsum(np.random.randn(n_points) * 0.0003)\nsequence = np.arange(n_points)\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Line segments with viridis gradient encoding trail progression\npoints = np.array([lon, lat]).T.reshape(-1, 1, 2)\nsegments = np.concatenate([points[:-1], points[1:]], axis=1)\nnorm = plt.Normalize(sequence.min(), sequence.max())\nlc = LineCollection(segments, cmap=\"viridis\", norm=norm, linewidth=2.5, alpha=0.9)\nlc.set_array(sequence[:-1])\nline = ax.add_collection(lc)\n\n# Colorbar\ncbar = fig.colorbar(line, ax=ax, shrink=0.8, pad=0.02)\ncbar.set_label(\"Trail Progress\", fontsize=10, color=INK_SOFT)\ncbar.ax.tick_params(labelsize=8, labelcolor=INK_SOFT, color=INK_SOFT)\ncbar.outline.set_edgecolor(INK_SOFT)\n\n# Start and end markers (Okabe-Ito positions 1 and 2)\nax.scatter(\n    lon[0], lat[0], s=150, c=START_COLOR, marker=\"o\", edgecolors=PAGE_BG, linewidths=1.5, zorder=5, label=\"Start\"\n)\nax.scatter(lon[-1], lat[-1], s=150, c=END_COLOR, marker=\"s\", edgecolors=PAGE_BG, linewidths=1.5, zorder=5, label=\"End\")\n\n# Direction arrows at intervals along the path\narrow_indices = np.linspace(20, n_points - 20, 5, dtype=int)\nfor i in arrow_indices:\n    dx = lon[i + 1] - lon[i - 1]\n    dy = lat[i + 1] - lat[i - 1]\n    ax.annotate(\n        \"\",\n        xy=(lon[i] + dx * 0.3, lat[i] + dy * 0.3),\n        xytext=(lon[i], lat[i]),\n        arrowprops={\"arrowstyle\": \"->\", \"color\": INK, \"lw\": 2.0},\n    )\n\n# Style\nax.set_xlabel(\"Longitude (°)\", fontsize=10, color=INK)\nax.set_ylabel(\"Latitude (°)\", fontsize=10, color=INK)\nax.set_title(\"map-route-path · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\n# Suppress offset notation so full coordinate values are shown\nax.ticklabel_format(useOffset=False, style=\"plain\")\n\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\n\nax.grid(True, alpha=0.12, linewidth=0.6, color=INK)\n\nleg = ax.legend(fontsize=8, loc=\"upper left\")\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\nx_margin = (lon.max() - lon.min()) * 0.1\ny_margin = (lat.max() - lat.min()) * 0.1\nax.set_xlim(lon.min() - x_margin, lon.max() + x_margin)\nax.set_ylim(lat.min() - y_margin, lat.max() + y_margin)\n\nplt.tight_layout()\n\n# Save — no bbox_inches so figsize×dpi gives exact 3200×1800\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}