Map Panel¶
The AI-Hydro map panel renders geospatial analysis outputs as interactive layers inside VS Code — watershed boundaries, TWI grids, gauge networks, GEE tiles, and any file you drop on the canvas appear here automatically. No copy-pasting coordinates into an external tool; no Mapbox token; no QGIS dependency.
The renderer is built on deck.gl (GPU-accelerated) and talks to the extension host over gRPC streaming so the map updates in real time as Python tools push layers.
Opening the Map¶
Click the Map icon in the AI-Hydro activity bar, or run AI-Hydro: Open Map from the command palette (Cmd+Shift+P). The panel opens in editor column 2, side-by-side with the chat.
Loading Files¶
Drag-and-drop¶
Drop any supported file directly onto the map canvas. A blue dashed drop zone appears while dragging. A toast at the bottom reports success or error and auto-dismisses after 4 seconds.
+ Add Layer (file picker)¶
Click + Add Layer… in the Layers panel to open a native file picker filtered to all supported extensions.
From VS Code Explorer (right-click)¶
Right-click a geospatial file in the Explorer panel and choose Add to AI-Hydro Map. The extension reads the file bytes and posts them directly to the webview without writing a temp copy.
Python tools (automatic)¶
Analysis tools push layers directly when they produce geometry — see Layers from Analysis Tools.
Supported File Formats¶
| Format | Extensions | Notes |
|---|---|---|
| GeoJSON | .geojson, .json | FeatureCollection, Feature, or bare Geometry |
| TopoJSON | .topojson, .json | Converted via topojson-client |
| KML | .kml | Placemarks, paths, and polygons via @tmcw/togeojson |
| KMZ | .kmz | ZIP extracted, inner KML parsed |
| GPX | .gpx | Track points and routes → GeoJSON |
| Shapefile | .zip | Zip must contain .shp + .dbf + .shx; .prj recommended |
| GeoTIFF | .tif, .tiff | Single-band raster; see GeoTIFF support |
| CSV | .csv | Auto-detects lon/lat/longitude/latitude/x/y columns |
GeoTIFF Support¶
GeoTIFFs are read with geotiff.js entirely in-browser. Supported CRSs:
| EPSG | Name |
|---|---|
| 4326, 4269, 4152 | WGS84 / NAD83 geographic — rendered directly |
| 3857, 900913 | Web Mercator — pixel-warped to WGS84 |
| 5070, 102003 | CONUS Albers (NLCD, POLARIS, 3DEP) — pixel-warped |
| 26901–26960 | NAD83 UTM zones 1–60 — pixel-warped |
| 32601–32660 | WGS84 UTM zones North — pixel-warped |
| 32701–32760 | WGS84 UTM zones South — pixel-warped |
| 26701–26760 | NAD27 UTM — pixel-warped |
| 25801–25860 | ETRS89 UTM — pixel-warped |
Warping: bilinear interpolation, output capped at 512 px on the long axis. Unsupported CRSs return a clear error; reproject to EPSG:4326 first using QGIS or gdalwarp.
Colormaps for GeoTIFFs default to viridis and can be changed in the Layers panel without reloading the file.
Tool Ribbon¶
The right-edge ribbon provides quick access to all map tools. Click an icon to open its panel; click again to collapse. Only one panel is open at a time.
| Icon | Tool | Description |
|---|---|---|
| 🗺️ | Basemap | Switch the base tile layer |
| 📑 | Layers | Layer list, symbology, reorder, export |
| 〰 | Hydrography | Load MERIT rivers, WBD boundaries |
| 🔍 | Search | Geocode a place and pin it on the map |
| 📐 | Measure | Distance or area measurement |
| ✏️ | Draw | Sketch polygons, lines, or points |
| 📤 | Export | Save map canvas as PNG |
| ⛶ | Fit extent | Zoom to all visible layers |
Basemaps¶
All basemaps are free — no API token required.
Hydrology-focused¶
| Basemap | Best for |
|---|---|
| USGS Topo (default) | Watershed context, roads, terrain names |
| USGS Imagery | Aerial / satellite verification |
| USGS Shaded Relief | Terrain hillshading |
| Esri Hillshade | High-resolution DEM shading |
| Esri Ocean | Bathymetry and coastal work |
General purpose¶
Carto Voyager, Carto Dark, Carto Light, Stadia Terrain, Esri World Topo, Esri Satellite, Humanitarian (HOT).
OpenStreetMap direct: tile.openstreetmap.org is run by volunteers and disallows embedded-app traffic. Use Carto or HOT basemaps for any deployed workflow — both are OSM-derived.
Layers Panel¶
The Layers panel lists all active layers and provides per-layer controls.
Layer type icons¶
| Icon | Layer type |
|---|---|
| ● | Point |
| 〰 | Line |
| ⬡ | Polygon |
| ▦ | Raster (local GeoTIFF) |
| ◉ | GEE tile layer |
| ◈ | Other / unknown |
Source badges¶
| Badge | Source |
|---|---|
| 📁 | Workspace file (auto-scanned on open) |
| 🐍 | Python tool output |
| 📥 | User-loaded (drag-and-drop / file picker) |
| 📤 | Pushed via extension API |
Per-layer controls¶
| Control | Action |
|---|---|
| Checkbox | Toggle visibility |
| Colour swatch | Open symbology editor |
| 🔍 | Zoom map to layer bounding box |
| 📊 | View attribute table (feature properties) |
| 💾 | Export layer as GeoJSON |
| ⠿ | Drag handle for reordering |
| ✕ | Remove layer (source file not deleted) |
Global controls¶
- Show all / Hide all — toggle all layers at once
- + Add Layer… — open file picker
- ⓘ — toggle metadata detail rows for all layers
Layer reordering¶
Drag a layer row using its ⠿ gripper to change render order. Layers at the bottom of the list render on top of all others.
Per-layer opacity¶
Each layer has an opacity slider (0–100%). For raster layers this blends against the basemap. For vector layers it multiplies against stroke and fill alpha.
Point clustering¶
For dense point networks (USGS gauges, precipitation stations), enable Cluster in the layer row. Points within the same grid cell at zoom < 8 are aggregated into a single marker sized by count. Clustering is computed per-zoom-level and cached per frame.
Symbology Editor¶
Click a layer's colour swatch or the 🎨 icon to open the inline editor. Changes apply live.
Vector layers¶
| Control | Effect |
|---|---|
| Fill colour | Feature fill (HTML colour picker) |
| Fill opacity | 0–1 slider |
| Stroke colour | Feature outline colour |
| Stroke width | Outline thickness (pixels) |
Raster / GEE tile layers¶
| Control | Effect |
|---|---|
| Colormap | viridis · viridis_r · plasma · magma · cividis · Blues · YlOrRd · RdYlGn · chirps |
| Opacity | 0–1 slider |
Graduated (choropleth) symbology¶
For vector layers, click Graduated… to open the graduated symbology editor:
- Select a numeric attribute from the layer's feature properties
- Choose a classification method: Natural Breaks, Equal Interval, or Quantile
- Pick a colour ramp: viridis, YlOrRd, Blues, RdYlGn, or custom stops
- Set the number of classes (2–7)
- Click Apply — breaks and colours are stored in layer metadata and re-applied on every render
The map legend updates automatically to show the colour ramp and class boundaries.
Measure Tool¶
Click the 📐 icon in the Tool Ribbon to activate measurement.
| Mode | How to use |
|---|---|
| Distance | Click two or more points; each segment shows its length in km/m; total length is shown in the toolbar |
| Area | Click three or more points to close a polygon; area is shown in km² or ha |
- Segment labels appear on the map at each midpoint (distance mode)
- Press ESC or click 📐 again to cancel
- Measurement geometry is rendered as an orange overlay layer that disappears when the tool closes
Distance uses the Haversine formula (great-circle distance on a sphere). Area uses the 2D planar approximation from the projected Mercator coordinates — accurate to within ~1% for basins up to ~100,000 km².
Vector Draw Tool¶
Click the ✏️ icon in the Tool Ribbon to draw geometry on the map.
| Mode | Geometry type |
|---|---|
| Polygon | Click vertices; double-click to close |
| Line | Click vertices; double-click to finish |
| Point | Single click to place |
After drawing:
- A green overlay shows the draft geometry
- A Save / Discard / Export panel appears
- Save — prompts for a name, saves as
roi/<name>.geojsonin your workspace root, registers as the active ROI - Export — downloads the GeoJSON directly to your Downloads folder
- Discard — clears the draft
The saved ROI is immediately available to all MCP tools via sessionId='map' — e.g. delineate_watershed_from_point, extract_hydrological_signatures.
Feature Inspector¶
Click anywhere on the map to open the Feature Inspector panel.
What it shows¶
- Coordinates — WGS84 lat/lon of the click point
- Vector features — properties of every visible vector feature at that point (deck.gl pick + point-in-polygon fallback for workspace layers)
- Raster value — pixel value of the topmost visible raster at that point (requires local GeoTIFF; not available for GEE tiles)
Actions in the Feature Inspector¶
| Button | Action |
|---|---|
| Quick Delineate | Runs delineatePoint command immediately — no chat opened; result appears on map within seconds |
| Delineate (agent) | Opens the chat with a pre-filled delineation prompt; the agent calls MCP tools |
| Ask AI | Opens the chat with a prompt describing the clicked location, visible layers, and feature properties |
Quick Delineate details:
- Inside CONUS: uses NLDI snap + NWM fallback (fast, ~5 seconds)
- Outside CONUS: requires MERIT river vectors on the map — loads them first via Hydrography → Load rivers if missing
- Adds watershed polygon + pour-point marker to the map and auto-fits bounds
- Reports area_km² and method_used in a status chip below the panel
Hydrography Panel¶
Click the 〰 icon in the Tool Ribbon to open the Hydrography panel. This provides one-click loading of global and US-specific hydrology reference layers.
| Button | Loads |
|---|---|
| MERIT rivers (region) | MERIT-Hydro river network for the current map view extent |
| MERIT rivers (basin) | MERIT-Hydro rivers for the active ROI basin |
| WBD / HUC boundaries | USGS Watershed Boundary Dataset at HUC 2/4/6/8 |
| HUC at point | Delineates which HUC polygon contains the current click point |
| Gauges in view | USGS stream gauges for the current map extent |
| Dams in view | NID dams for the current map extent |
All layers arrive via the MCP server and are pushed through the gRPC layer subscription — they appear on the map without a page reload.
Location Search¶
Click the 🔍 icon in the Tool Ribbon to open the search bar.
- Type a place name, address, or geographic feature
- Results appear as you type (Nominatim geocoding via OpenStreetMap)
- Click a result to fly to it and drop a pulsing pin marker
- Click ✕ on the pin card to clear it
The search uses the current map viewport as a geographic bias so results near the basin of interest rank higher.
Map Export¶
Click the 📤 icon in the Tool Ribbon to export the current map canvas as a PNG. The deck.gl canvas is captured at its current resolution and downloaded with a timestamp filename (ai-hydro-map-YYYY-MM-DDTHH-MM-SS.png).
Tile completeness: the export captures whatever tiles are currently loaded. Zoom in before exporting for higher-detail imagery.
Map Status Bar¶
The bar at the bottom of the map shows:
| Element | Detail |
|---|---|
| Scale bar | Physical distance per pixel at current zoom and latitude |
| Coordinates | Cursor position — click to cycle between decimal (45.4981°N), DMS (45°29'53.2"N), and UTM |
| Bearing indicator | Compass needle; click to reset north |
| Zoom controls | +/– buttons |
| Attribution | Basemap source links (required by tile licenses) |
Layers from Analysis Tools¶
Once the AI-Hydro Python backend is installed and configured, analysis tools push layers automatically:
| Tool | Layer pushed | Type |
|---|---|---|
delineate_watershed | Watershed boundary polygon + outlet point | Vector |
compute_twi | TWI grid (viridis_r, 70% opacity) | Raster |
create_cn_grid | Curve Number grid (YlOrRd, 70% opacity) | Raster |
show_on_map | Any GeoJSON you pass | Vector |
gee.preview_layer | Google Earth Engine tile mosaic | GEE tile |
merit_add_map_layers | MERIT river network for a basin | Vector |
wbd_add_map_layers | WBD HUC boundaries | Vector |
show_on_map Tool¶
Push any geometry from your Python analysis session directly to the map:
show_on_map(
geojson=my_geojson_string, # FeatureCollection / Feature / Geometry
name="Study Area",
layer_type="polygon", # polygon | line | point
style_preset="watershed", # watershed | flowlines | gauge | default
auto_zoom=True,
)
Style presets
| Preset | Fill colour | Stroke | Use for |
|---|---|---|---|
watershed | #1a6eb5 (20% opacity) | #003399 | Catchment polygons |
flowlines | transparent | #3399ff | River / stream lines |
gauge | #e05c00 | #993300 | Station point markers |
default | #0066CC | #003399 | General purpose |
Per-key overrides:
show_on_map(
geojson=aoi_geojson,
name="Custom AOI",
fill_color="#FF5733",
stroke_color="#CC3300",
fill_opacity=0.4,
stroke_width=2,
)
Agent Map Orchestration¶
The agent can read map state and update layers without creating duplicate geometry files.
Reading map state¶
map_get_state → basemap, view center/zoom, active ROI, full layer catalog
map_list_layers → layer catalog only (ids, names, types, styles, numeric attributes)
Updating existing layers¶
map_update_layer(layer_id, fill_color, stroke_color, opacity, display_name, visible)
map_apply_symbology(layer_id, graduated_attribute, method, classes, color_ramp)
map_remove_layer(layer_id)
Viewport control¶
map_fit_extent → fit all visible layers
map_fit_layer(layer_id) → fit a specific layer
map_set_basemap(id) → change basemap
Do not write a second GeoJSON file just to re-style a layer that is already on the map. Use
map_update_layerfor style changes;show_on_maponly when adding new geometry.
Workspace Persistence¶
Map state is saved to localStorage key aihydro.map.workspace.v1 on every change and restored automatically on next open:
- Selected basemap
- View state (longitude, latitude, zoom, pitch, bearing)
- Visible layer IDs
- Per-layer opacity overrides
- Clustering-enabled layer IDs
- Ribbon panel dimensions (width × height)
Keyboard Shortcuts¶
| Key | Action |
|---|---|
Esc | Cancel active draw / measure / close search or export panel |
+ / - | Zoom in / out (status bar buttons) |
| Click scale | Cycle coordinate display format (decimal → DMS → UTM) |
How the Python ↔ Map Bridge Works¶
When a Python tool calls show_on_map or any map-aware MCP tool, the flow is:
- MCP tool calls
ai_hydro.mcp.map_events.push_layer(layer)on the server - The server writes a small JSON event to
~/.aihydro/map_events/ - The VS Code extension file-watcher picks it up (~600 ms polling), calls
controller.addMapLayer(), and deletes the file - The controller forwards the layer over the gRPC
MapService.subscribeToMapLayersstream MapContextreceives the stream event and updates React state — deck.gl re-renders
For GEE tile layers, the Python tool computes the tile URL template using geemap and passes it in the metadata.gee_tile_url_template field. The map renders tiles via a deck.gl TileLayer fetching each tile directly from the GEE Maps API (requires authenticated GEE session on the Python side).
Layers pushed while the map was closed are queued in the controller's in-memory store and delivered the next time the panel connects to the gRPC stream.