{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "interactive-map-intro",
      "metadata": {},
      "source": "# Offline notebook maps: pan, zoom and revealing labels\n\nRun this notebook with the matching chart enabled native runtime and compatible Aner VS Code extension. The first chart needs **no map pack**. The optional final chart needs only `usa.co`; transfer its matching `.anermap` file and install locally with `aner maps install FILE.anermap`. Use the same `ANER_MAPS_DIR` for the runtime and notebook processes if you override the map store.\n\nAll station locations, indices and totals are invented teaching data near downtown Boulder. Their grid does not identify real stations, property boundaries or surveyed sites. Color and marker area encode separate synthetic variables. No geocoding, spatial membership test or aggregation is performed.\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "interactive-map-imports",
      "metadata": {},
      "outputs": [],
      "source": [
        "// Interactive navigation is provided by the compatible Aner VS Code extension.\n",
        "// The first chart requires no map pack. The second requires only usa.co.\n",
        "// Locations and values below are invented observations near downtown Boulder.\n",
        "import aner.plot\n",
        "import aner.geo\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "interactive-map-stations",
      "metadata": {},
      "outputs": [],
      "source": [
        "let stationPositions = List(\n",
        "    geo.position(longitude: -105.2760, latitude: 40.0120),\n",
        "    geo.position(longitude: -105.2735, latitude: 40.0120),\n",
        "    geo.position(longitude: -105.2710, latitude: 40.0120),\n",
        "    geo.position(longitude: -105.2685, latitude: 40.0120),\n",
        "    geo.position(longitude: -105.2760, latitude: 40.0140),\n",
        "    geo.position(longitude: -105.2735, latitude: 40.0140),\n",
        "    geo.position(longitude: -105.2710, latitude: 40.0140),\n",
        "    geo.position(longitude: -105.2685, latitude: 40.0140),\n",
        "    geo.position(longitude: -105.2760, latitude: 40.0160),\n",
        "    geo.position(longitude: -105.2735, latitude: 40.0160),\n",
        "    geo.position(longitude: -105.2710, latitude: 40.0160),\n",
        "    geo.position(longitude: -105.2685, latitude: 40.0160),\n",
        "    geo.position(longitude: -105.2760, latitude: 40.0180),\n",
        "    geo.position(longitude: -105.2735, latitude: 40.0180),\n",
        "    geo.position(longitude: -105.2710, latitude: 40.0180),\n",
        "    geo.position(longitude: -105.2685, latitude: 40.0180))\n",
        "let stationValues = List(8.0, 12.0, 15.0, 11.0, 18.0, 9.0, 14.0, 17.0,\n",
        "    10.0, 13.0, 19.0, 16.0, 7.0, 20.0, 21.0, 6.0)\n",
        "let stationTotals = List(12.0, 18.0, 24.0, 16.0, 30.0, 14.0, 22.0, 28.0,\n",
        "    15.0, 20.0, 32.0, 26.0, 10.0, 34.0, 36.0, 8.0)\n",
        "let stationLabels = List(\"Station 01\", \"Station 02\", \"Station 03\", \"Station 04\",\n",
        "    \"Station 05\", \"Station 06\", \"Station 07\", \"Station 08\",\n",
        "    \"Station 09\", \"Station 10\", \"Station 11\", \"Station 12\",\n",
        "    \"Station 13\", \"Station 14\", \"Station 15\", \"Station 16\")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "interactive-map-pack-free-context",
      "metadata": {},
      "source": "## Reveal the dense cluster without any boundary pack\n\nRun the chart, then zoom around its central cluster with **+**, double click, or **Ctrl**/**Cmd** + wheel. Drag to pan. With the map focused, **+**/**−** zoom, arrow keys pan and **Home** resets; the toolbar also provides **Reset**. Plain wheel scrolling continues to scroll the notebook.\n\nThe overview deliberately crowds sixteen nearby observations. `point_labels(\"avoid\")` places labels in observation order and tries eight nearby locations for each. Zoom creates room for previously hidden labels. Markers and text retain their drawing sizes; color and circle area domains remain fixed. Coincident observations would still be crowded at any zoom. Full supplied labels and values remain in tooltips. Use `point_labels(\"all\")` to permit overlaps or `point_labels(\"none\")` to hide point text.\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "interactive-map-pack-free",
      "metadata": {},
      "outputs": [],
      "source": [
        "// Pack-free point chart: zoom into the cluster to reveal more station labels.\n",
        "let stations = plot.geo_scatter(positions: stationPositions,\n",
        "    values: stationValues, labels: stationLabels)\n",
        "    .point_sizes(values: stationTotals, max_radius: 7.0)\n",
        "    .point_labels(\"avoid\")\n",
        "    .extent(west: -105.34, south: 39.96, east: -105.20, north: 40.09)\n",
        "    .projection(\"lambert_azimuthal_equal_area\")\n",
        "    .size(width: 900, height: 620)\n",
        "    .title(\"Boulder: zoom into sixteen illustrative stations\")\n",
        "    .caption(\"Invented observations; color is a synthetic index, circle area is a separate synthetic total. No map pack.\")\n",
        "stations.show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "interactive-map-boulder-context",
      "metadata": {},
      "source": "## Optional Boulder municipal context\n\nInstall **only `usa.co`** before running the next cell. It adds generalized Census 2025 place geometry behind the same supplied points. The map and point layers share the fixed local Lambert azimuthal equal area display projection. Source generalization remains visible at higher zoom; navigation cannot add streets or recover omitted boundary detail.\n\nNavigation is bounded to the chart’s initial extent. Begin with a broader extent to explore more territory in one output, then zoom and pan within it. Projection parameters remain those of that initial view. For a reproducible chosen viewport, edit `extent(...)` and rerun. Interactive navigation does not change the stored chart or the initial view used by `svg`/`save`.\n"
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "interactive-map-boulder",
      "metadata": {},
      "outputs": [],
      "source": [
        "// Optional usa.co pack: generalized Census 2025 Boulder municipal context.\n",
        "plot.map(\"usa.co.places\", keys: List(\"0807850\"), values: List(20.0))\n",
        "    .add_points(positions: stationPositions, values: stationValues, labels: stationLabels)\n",
        "    .point_sizes(values: stationTotals, max_radius: 7.0)\n",
        "    .point_labels(\"avoid\")\n",
        "    .extent(west: -105.34, south: 39.96, east: -105.20, north: 40.09)\n",
        "    .projection(\"lambert_azimuthal_equal_area\")\n",
        "    .size(width: 900, height: 620)\n",
        "    .title(\"The same stations over Boulder municipal geometry\")\n",
        "    .caption(\"Invented observations; synthetic index and total. Generalized Census 2025 place geometry; optional usa.co pack.\")\n",
        "    .show()\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "interactive-map-saved-output",
      "metadata": {},
      "source": "## Save and reopen offline\n\nThe renderer is bundled with the extension. Pan, zoom and label layout make no network or native session requests. Save `.anernb` after running to retain its bounded geographic scenes and SVG fallbacks. Reopen with the compatible extension to navigate the saved scenes offline without a running kernel or the source packs. Rerunning boundary code needs its pack again. View changes are temporary; reopening restores the original saved scene.\n\nLarge scenes fall back to static SVG when the additional interactive data cannot fit its 2 MiB scene budget or the 4 MiB cell display envelope. The first chart uses sixteen supplied positions and no optional map data. Other notebook clients, including the optional Jupyter adapter, retain static SVG display.\n"
    }
  ],
  "metadata": {
    "kernelspec": {
      "name": "aner",
      "display_name": "Aner",
      "language": "aner"
    },
    "language_info": {
      "name": "aner",
      "file_extension": ".aner",
      "mimetype": "text/x-aner"
    },
    "aner": {
      "status": "example",
      "execution_mode": "persistent-session"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
