georest.usgs.nldi

Client for the USGS Hydro Network-Linked Data Index (NLDI).

The NLDI ties things that sit on rivers (stream gages, water-quality sites, dams, pour points and more) to the NHDPlus river network, and lets you walk that network: upstream or downstream from any point, along the main stem or into every tributary, listing the flowlines or the sites you pass. It also delineates the basin that drains to a point.

A typical question takes two calls: find the river reach at a point, then navigate from it:

from georest.usgs import nldi

reach = nldi.find_flowline(-111.596, 36.866)     # the NHDPlus reach (COMID)
gages = nldi.sites_along("comid", reach["comid"], "upstream_tributaries",
                         distance_km=100)          # a DataFrame of gages

Everything that starts from a feature takes a source and an identifier: ("comid", 18267741) for a river reach, ("nwissite", "USGS-09380000") for a USGS gage, and so on; list_sources() lists them all. Navigation modes accept the friendly names ("upstream", "upstream_tributaries", "downstream", "downstream_diversions") or NLDI’s codes (UM, UT, DM, DD).

Tables come back as pandas DataFrames, with point coordinates as lon and lat. Flowlines and basins are shapes, so they come back as GeoJSON.

Copyright 2026 Ryan Rock and Ian Housman

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Module Attributes

MODES

Navigation modes, by friendly name, onto NLDI's codes.

Functions

basin(source, identifier, *[, simplified, ...])

The drainage basin upstream of a feature.

find_flowline(lon, lat)

The NHDPlus river reach nearest a point.

flowlines(source, identifier[, mode, ...])

The river reaches you pass navigating from a feature.

get_feature(source, identifier)

One linked feature, such as a USGS gage, with where it joins the network.

list_sources()

Every kind of feature the NLDI links to the river network.

sites_along(source, identifier[, mode, ...])

The linked sites you pass navigating from a feature.

georest.usgs.nldi.MODES = {'downstream': 'DM', 'downstream_diversions': 'DD', 'downstream_main': 'DM', 'upstream': 'UM', 'upstream_main': 'UM', 'upstream_tributaries': 'UT'}

Navigation modes, by friendly name, onto NLDI’s codes.

georest.usgs.nldi.list_sources() → Any[source]

Every kind of feature the NLDI links to the river network.

Returns:

pandas.DataFrame with source (the name to pass as source= or data_source=), name and url.

Example:

from georest.usgs import nldi

nldi.list_sources()   # nwissite (USGS gages), WQP, ref_dams, huc12pp, ...
georest.usgs.nldi.find_flowline(lon: float, lat: float) → dict[source]

The NHDPlus river reach nearest a point.

Parameters:
  • lon – The point, in decimal degrees.

  • lat – The point, in decimal degrees.

Returns:

its comid (pass it on as ("comid", reach["comid"])) and the other properties at the top level of the dict, and the reach’s line under geometry.

Return type:

The reach as a GeoJSON Feature

Example:

from georest.usgs import nldi

reach = nldi.find_flowline(-111.596, 36.866)
reach["comid"]   # an NHDPlus COMID, e.g. 18267741
georest.usgs.nldi.get_feature(source: str, identifier: str | int) → dict[source]

One linked feature, such as a USGS gage, with where it joins the network.

Returns:

The feature’s properties (name, comid of the reach it sits on, uri, …) plus lon and lat.

Example:

from georest.usgs import nldi

gage = nldi.get_feature("nwissite", "USGS-09380000")
gage["name"], gage["comid"]   # 'COLORADO RIVER AT LEES FERRY, AZ', 20733845
georest.usgs.nldi.flowlines(source: str, identifier: str | int, mode: str = 'upstream', *, distance_km: float = 50) → dict[source]

The river reaches you pass navigating from a feature.

Parameters:
  • source – Where to start, e.g. ("comid", 18267741) or ("nwissite", "USGS-09380000").

  • identifier – Where to start, e.g. ("comid", 18267741) or ("nwissite", "USGS-09380000").

  • mode – "upstream" (main stem), "upstream_tributaries", "downstream" or "downstream_diversions".

  • distance_km – How far to go. Required: without it NLDI walks the whole network.

Returns:

A GeoJSON FeatureCollection of LineStrings, one per NHDPlus reach, each with its nhdplus_comid.

Example:

from georest.usgs import nldi

river = nldi.flowlines("nwissite", "USGS-09380000", "upstream", distance_km=25)
len(river["features"])   # reaches within 25 km upstream of Lees Ferry
georest.usgs.nldi.sites_along(source: str, identifier: str | int, mode: str = 'upstream', *, data_source: str = 'nwissite', distance_km: float = 50) → Any[source]

The linked sites you pass navigating from a feature.

Parameters:
  • source – Where to start.

  • identifier – Where to start.

  • mode – "upstream", "upstream_tributaries", "downstream" or "downstream_diversions".

  • data_source – Which sites to list: "nwissite" (USGS stream gages, the default), "WQP" (Water Quality Portal sites), "ref_dams", "huc12pp", …; see list_sources().

  • distance_km – How far to go. Required: without it NLDI walks the whole network.

Returns:

identifier, name, comid, uri and the rest of NLDI’s properties, plus lon and lat.

Return type:

pandas.DataFrame, one row per site

Example:

from georest.usgs import nldi

# Every USGS gage on the river and its tributaries within 100 km
# upstream of Lees Ferry
gages = nldi.sites_along("nwissite", "USGS-09380000", "upstream_tributaries",
                         distance_km=100)
gages[["identifier", "name"]]
georest.usgs.nldi.basin(source: str, identifier: str | int, *, simplified: bool = True, split_catchment: bool = False) → dict[source]

The drainage basin upstream of a feature.

Parameters:
  • source – The outlet, e.g. ("nwissite", "USGS-09380000").

  • identifier – The outlet, e.g. ("nwissite", "USGS-09380000").

  • simplified – Return a lighter, simplified outline (the default). Full detail can run to megabytes for a large basin.

  • split_catchment – Split the outlet’s own catchment at the exact point instead of including all of it. Slower; matters for small basins.

Returns:

A GeoJSON FeatureCollection holding one (Multi)Polygon.

Example:

from georest.usgs import nldi

drains_to_lees_ferry = nldi.basin("nwissite", "USGS-09380000")
drains_to_lees_ferry["features"][0]["geometry"]["type"]   # 'MultiPolygon'