{"spec_id":"map-route-path","library":"letsplot","language":"python","code":"\"\"\" anyplot.ai\nmap-route-path: Route Path Map\nLibrary: letsplot 4.10.1 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom lets_plot import (\n    LetsPlot,\n    aes,\n    coord_fixed,\n    element_line,\n    element_rect,\n    element_text,\n    geom_path,\n    geom_point,\n    ggplot,\n    ggsize,\n    labs,\n    layer_tooltips,\n    scale_color_viridis,\n    scale_fill_manual,\n    theme,\n    theme_minimal,\n)\nfrom lets_plot.export import ggsave\n\n\nLetsPlot.setup_html()\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\"\nTERRAIN_BG = \"#E8F0E4\" if THEME == \"light\" else \"#1D2419\"\n\n# Data — Swiss Alps hiking trail (GPS track simulation)\nnp.random.seed(42)\nstart_lat, start_lon = 46.85, 9.85\nn_points = 150\n\nt = np.linspace(0, 4 * np.pi, n_points)\nlat_offset = np.cumsum(np.sin(t) * 0.002 + np.random.randn(n_points) * 0.0003)\nlon_offset = np.cumsum(np.cos(t * 0.7) * 0.003 + np.random.randn(n_points) * 0.0004)\n\nlat = start_lat + lat_offset\nlon = start_lon + lon_offset\nsequence = np.arange(n_points)\n\ndf = pd.DataFrame({\"lat\": lat, \"lon\": lon, \"sequence\": sequence, \"progress\": sequence / (n_points - 1) * 100})\n\nstart_pt = df.iloc[[0]].copy()\nstart_pt[\"marker\"] = \"Start\"\nend_pt = df.iloc[[-1]].copy()\nend_pt[\"marker\"] = \"End\"\nmarkers_df = pd.concat([start_pt, end_pt], ignore_index=True)\n\n# Plot\nanyplot_theme = theme(\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=TERRAIN_BG),\n    panel_grid_major=element_line(color=INK_SOFT, size=0.3),\n    panel_grid_minor=element_line(color=INK_SOFT, size=0.15),\n    axis_title=element_text(color=INK, size=12),\n    axis_text=element_text(color=INK_SOFT, size=10),\n    plot_title=element_text(color=INK, size=16),\n    legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n    legend_text=element_text(color=INK_SOFT, size=10),\n    legend_title=element_text(color=INK, size=10),\n)\n\nplot = (\n    ggplot()\n    + geom_path(\n        aes(x=\"lon\", y=\"lat\", color=\"progress\"),\n        data=df,\n        size=1.5,\n        alpha=0.9,\n        tooltips=layer_tooltips()\n        .line(\"Progress|@progress%\")\n        .line(\"Lat|@lat\")\n        .line(\"Lon|@lon\")\n        .format(\"@progress\", \".1f\")\n        .format(\"@lat\", \".4f\")\n        .format(\"@lon\", \".4f\"),\n    )\n    + geom_point(\n        aes(x=\"lon\", y=\"lat\", fill=\"marker\"),\n        data=markers_df,\n        size=5,\n        shape=21,\n        stroke=2,\n        color=\"white\",\n        tooltips=layer_tooltips().line(\"@marker\"),\n    )\n    + scale_color_viridis(name=\"Progress (%)\")\n    + scale_fill_manual(values={\"Start\": \"#009E73\", \"End\": \"#C475FD\"}, name=\"Markers\")\n    + labs(x=\"Longitude (°)\", y=\"Latitude (°)\", title=\"map-route-path · python · letsplot · anyplot.ai\")\n    + theme_minimal()\n    + anyplot_theme\n    + coord_fixed(ratio=1.0)\n    + ggsize(800, 450)\n)\n\n# Save\nggsave(plot, f\"plot-{THEME}.png\", path=\".\", scale=4)\nggsave(plot, f\"plot-{THEME}.html\", path=\".\")\n"}