Client Libraries

Python and R client libraries for the NLDI — PyNHD (HyRiver), dataRetrieval, and nhdplusTools — with examples paralleling the core API documentation.

Client Libraries

The NLDI can be accessed directly via HTTP (see Getting Started ), but client libraries handle request construction, pagination, and geospatial output formatting so you can focus on analysis rather than URL assembly.

Three libraries cover the most common workflows:

  • PythonPyNHD , part of the HyRiver suite
  • RdataRetrieval , the most widely used USGS data access package, with a convenience NLDI interface
  • RnhdplusTools , granular NLDI functions for spatial and network analysis

The examples below parallel the topics covered in the sibling documentation pages — Feature Sources , Navigation , and Basin and Hydrolocation — and show how to accomplish each operation using the library rather than raw HTTP.


Python — PyNHD (HyRiver)

PyNHD is the NLDI component of the HyRiver suite, a collection of Python packages for retrieving hydrological and meteorological data from web services. Companion packages (PyGeoHydro, PyDaymet, Py3DEP, etc.) complement NLDI navigation with streamflow, climate, and elevation data.

All NLDI functions are accessed through the NLDI() class. Output is always a GeoPandas GeoDataFrame in EPSG:4326.

Install via conda (recommended for geospatial work) or pip:

conda install -c conda-forge pynhd

pip install pynhd

Feature Sources

See Registered Feature Sources for full API semantics. Feature sources in PyNHD are referenced by string — "nwissite", "huc12pp", "comid", etc.

from pynhd import NLDI

nldi = NLDI()

# Retrieve the NLDI record for a NWIS surface-water site
site = nldi.getfeature_byid("nwissite", "USGS-05428500")
site
                     geometry  ...                                   mainstem
0  POINT (-89.36083 43.08944)  ...  https://geoconnex.us/ref/mainstems/377002

[1 rows x 12 columns]

The comid feature source’s position endpoint is available through comid_byloc():

# Find the NHDPlusV2 catchment containing a point
# Coordinates are (longitude, latitude)
comid = nldi.comid_byloc((-89.35, 43.0864))
comid
                     geometry identifier  ...           type uri
0  POINT (-89.35306 43.08451)             ...  hydrolocation    

[1 rows x 11 columns]

See Navigation Modes for endpoint structure and mode descriptions. The navigate_byid() method wraps the /navigation/{mode}/{dataSource}?distance= endpoint.

PyNHD uses descriptive strings for navigation modes:

PyNHD string API mode Description
"upstreamMain" UM Upstream mainstem
"upstreamTributaries" UT Upstream with tributaries
"downstreamMain" DM Downstream mainstem
"downstreamDiversions" DD Downstream with diversions
# Navigate upstream with tributaries from a NWIS gage, returning flowlines
flowlines = nldi.navigate_byid(
    fsource="nwissite",
    fid="USGS-05428500",
    navigation="upstreamTributaries",
    source="flowlines",
    distance=100,
)

print(f"{len(flowlines)} flowlines returned")
168 flowlines returned
flowlines.head()
                                            geometry nhdplus_comid
0  LINESTRING (-89.37037 43.09491, -89.36997 43.0...      13293750
1  LINESTRING (-89.38441 43.09903, -89.38351 43.0...      13294312
2  LINESTRING (-89.37836 43.12705, -89.37849 43.1...      13294308
3  LINESTRING (-89.41003 43.10678, -89.40898 43.1...      13294310
4  LINESTRING (-89.37711 43.1276, -89.37836 43.12...      13293634
# Collect all NWIS sites within 100 km upstream
nwis_sites = nldi.navigate_byid(
    fsource="nwissite",
    fid="USGS-05428500",
    navigation="upstreamTributaries",
    source="nwissite",
    distance=100,
)

print(f"{len(nwis_sites)} NWIS sites found upstream")
53 NWIS sites found upstream
nwis_sites.head()
                     geometry  ...                                   mainstem
0  POINT (-89.43683 43.14683)  ...  https://geoconnex.us/ref/mainstems/467897
1  POINT (-89.43683 43.14683)  ...  https://geoconnex.us/ref/mainstems/467897
2    POINT (-89.37012 43.095)  ...  https://geoconnex.us/ref/mainstems/377002
3  POINT (-89.44231 43.14028)  ...                                        NaN
4  POINT (-89.47186 43.14506)  ...                                        NaN

[5 rows x 12 columns]

The distance parameter is always in kilometers and must be provided explicitly.

Basin and Hydrolocation

See Basin and Hydrolocation for algorithm details including the split-catchment and raindrop-trace workflows.

# Retrieve the full upstream basin polygon (simplified by default)
basin = nldi.get_basins(
    feature_ids="USGS-05428500",
    fsource="nwissite",
)
basin
                                                        geometry
identifier                                                      
USGS-05428500  POLYGON ((-89.35738 43.11701, -89.35423 43.115...

feature_ids accepts a single string or a list of IDs from the same fsource. simplified=True (the default) returns a reduced-vertex polygon suitable for display; set simplified=False for full-resolution geometry.

Location-based hydrolocation snaps a coordinate to the nearest flowline:

# Snap a coordinate to the nearest flowline (within 200 m)
# or trace via the raindrop algorithm
feature = nldi.feature_byloc((-89.35, 43.0864))
feature
                                            geometry  ...     comid
0  LINESTRING (-89.35393 43.08521, -89.35385 43.0...  ...  13294318

[1 rows x 6 columns]

R — dataRetrieval

dataRetrieval is the most widely used USGS R package for retrieving water data from NWIS, WQP, and related services. Its findNLDI() function provides a single-call interface that combines feature lookup, navigation, and basin retrieval — it is the fastest path from “I have a gage ID” to “I have upstream features and data.”

Install from CRAN:

install.packages("dataRetrieval")

Feature Sources

See Registered Feature Sources for full API semantics. findNLDI() accepts a starting point through named arguments — nwis, comid, wqp, huc12, or location for coordinates — so you do not need to construct a feature-source string manually.

library(dataRetrieval)

# Look up the NLDI record for a NWIS site
result <- findNLDI(nwis = "05428500")

# result$origin is an sf point with the gage's NLDI attributes
result$origin
Simple feature collection with 1 feature and 8 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -89.36083 ymin: 43.08944 xmax: -89.36083 ymax: 43.08944
Geodetic CRS:  WGS 84
# A tibble: 1 × 9
  sourceName               identifier  comid name  reachcode measure     X     Y
  <chr>                    <chr>       <int> <chr> <chr>       <dbl> <dbl> <dbl>
1 NWIS Surface Water Sites USGS-0542… 1.33e7 YAHA… 07090002…    42.0 -89.4  43.1
# ℹ 1 more variable: geometry <POINT [°]>

To list all available feature sources:

get_nldi_sources()
              source                                            sourceName
1           ca_gages                        Streamgage catalog for CA SB19
2  census2020-nhdpv2 2020 Census Block - NHDPlusV2 Catchment Intersections
3           epa_nrsa            EPA National Rivers and Streams Assessment
4     geoconnex-demo                     geoconnex contribution demo sites
5         gfv11_pois        USGS Geospatial Fabric V1.1 Points of Interest
6              GRAND                             Selected GRAND Reservoirs
7            HILARRI                     HILARRI Hydropower Infrastructure
8            huc12pp                           HUC12 Pour Points NHDPlusV2
9     huc12pp_102020                       HUC12 Pour Points circa 10-2020
10          nmwdi-st                 New Mexico Water Data Initative Sites
11             npdes              NPDES Facilities that Discharge to Water
12            nwisgw                                NWIS Groundwater Sites
13          nwissite                              NWIS Surface Water Sites
14          ref_dams                           geoconnex.us reference dams
15          ref_gage                          geoconnex.us reference gages
16             vigil                                    Vigil Network Data
17              wade                         Water Data Exchange 2.0 Sites
18       wade_rights                      Water Data Exchange Water Rights
19   wade_timeseries                       Water Data Exchange Time Series
20               WQP                                  Water Quality Portal
21             comid                                         NHDPlus comid
                                                        features
1           https://api.water.usgs.gov/nldi/linked-data/ca_gages
2  https://api.water.usgs.gov/nldi/linked-data/census2020-nhdpv2
3           https://api.water.usgs.gov/nldi/linked-data/epa_nrsa
4     https://api.water.usgs.gov/nldi/linked-data/geoconnex-demo
5         https://api.water.usgs.gov/nldi/linked-data/gfv11_pois
6              https://api.water.usgs.gov/nldi/linked-data/grand
7            https://api.water.usgs.gov/nldi/linked-data/hilarri
8            https://api.water.usgs.gov/nldi/linked-data/huc12pp
9     https://api.water.usgs.gov/nldi/linked-data/huc12pp_102020
10          https://api.water.usgs.gov/nldi/linked-data/nmwdi-st
11             https://api.water.usgs.gov/nldi/linked-data/npdes
12            https://api.water.usgs.gov/nldi/linked-data/nwisgw
13          https://api.water.usgs.gov/nldi/linked-data/nwissite
14          https://api.water.usgs.gov/nldi/linked-data/ref_dams
15          https://api.water.usgs.gov/nldi/linked-data/ref_gage
16             https://api.water.usgs.gov/nldi/linked-data/vigil
17              https://api.water.usgs.gov/nldi/linked-data/wade
18       https://api.water.usgs.gov/nldi/linked-data/wade_rights
19   https://api.water.usgs.gov/nldi/linked-data/wade_timeseries
20               https://api.water.usgs.gov/nldi/linked-data/wqp
21             https://api.water.usgs.gov/nldi/linked-data/comid

See Navigation Modes for mode descriptions and the distance parameter. The nav argument accepts the two-letter mode codes ("UM", "UT", "DM", "DD") and the find argument specifies which data sources to return.

# Navigate upstream with tributaries from a NWIS site
# Collect flowlines within 100 km
ut_flowlines <- findNLDI(
  nwis = "05428500",
  nav = "UT",
  find = c("flowlines"),
  distance_km = 100
)

head(ut_flowlines$UT_flowlines)
Simple feature collection with 6 features and 1 field
Geometry type: LINESTRING
Dimension:     XY
Bounding box:  xmin: -89.42124 ymin: 43.08521 xmax: -89.35393 ymax: 43.1326
Geodetic CRS:  WGS 84
# A tibble: 6 × 2
  nhdplus_comid                                                         geometry
  <chr>                                                         <LINESTRING [°]>
1 13293750      (-89.37037 43.09491, -89.36997 43.09475, -89.36916 43.09425, -8…
2 13294312      (-89.38441 43.09903, -89.38351 43.09872, -89.3824 43.09866, -89…
3 13294308      (-89.37836 43.12705, -89.37849 43.12689, -89.38291 43.12426, -8…
4 13294310      (-89.41003 43.10678, -89.40898 43.10619, -89.40492 43.10585, -8…
5 13293634                               (-89.37711 43.1276, -89.37836 43.12705)
6 13294304      (-89.42001 43.1326, -89.42044 43.13194, -89.42124 43.12364, -89…
# Collect upstream NWIS sites within 100 km
ut_sites <- findNLDI(
  nwis = "05428500",
  nav = "UT",
  find = c("nwissite"),
  distance_km = 100
)

head(ut_sites$UT_nwissite)
Simple feature collection with 6 features and 8 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -89.52151 ymin: 43.09861 xmax: -89.26123 ymax: 43.2011
Geodetic CRS:  WGS 84
# A tibble: 6 × 9
  sourceName               identifier  comid name  reachcode measure     X     Y
  <chr>                    <chr>       <int> <chr> <chr>       <dbl> <dbl> <dbl>
1 NWIS Surface Water Sites USGS-0542… 1.33e7 TOKE… 07090002…   12.1  -89.3  43.2
2 NWIS Surface Water Sites USGS-0542… 1.33e7 DORN… 07090002…   15.9  -89.4  43.1
3 NWIS Surface Water Sites USGS-0542… 1.33e7 PHEA… 07090002…   40.7  -89.5  43.1
4 NWIS Surface Water Sites USGS-0542… 1.33e7 SIXM… 07090002…    1.83 -89.5  43.2
5 NWIS Surface Water Sites USGS-0542… 1.33e7 SIXM… 07090002…   82.6  -89.5  43.2
6 NWIS Surface Water Sites USGS-0542… 1.33e7 S FO… 07090002…   53.8  -89.5  43.1
# ℹ 1 more variable: geometry <POINT [°]>

Start from a coordinate instead of a known feature:

result_loc <- findNLDI(
  location = c(-89.35, 43.0864),
  nav = "UT",
  find = c("flowlines"),
  distance_km = 50
)

nrow(result_loc$UT_flowlines)
[1] 169

Basin

See Basin and Hydrolocation for algorithm details. "basin" is a special value in the find argument that retrieves the full upstream drainage polygon.

result <- findNLDI(
  nwis = "05428500",
  find = c("basin")
)

result$basin
Simple feature collection with 1 feature and 0 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -89.60465 ymin: 43.03507 xmax: -89.20378 ymax: 43.36607
Geodetic CRS:  WGS 84
# A tibble: 1 × 1
                                                                        geometry
                                                                   <POLYGON [°]>
1 ((-89.35738 43.11701, -89.35423 43.11546, -89.35437 43.11067, -89.34997 43.10…

R — nhdplusTools

nhdplusTools provides separate functions that map directly to individual NLDI endpoints, giving fine-grained control over each step. It returns sf data frames in WGS 84 and is best suited for spatial and network analysis workflows that go beyond simple feature discovery.

Install from CRAN:

install.packages("nhdplusTools")

All nhdplusTools NLDI functions take an nldi_feature argument — a named list that maps directly to the {featureSource}/{featureID} URL structure documented in Getting Started :

library(nhdplusTools)

nldi_feature <- list(featureSource = "nwissite", featureID = "USGS-05428500")

Feature Sources

See Registered Feature Sources for full API semantics.

# List all available feature sources
sources <- get_nldi_sources()
head(sources)
             source                                            sourceName
1          ca_gages                        Streamgage catalog for CA SB19
2 census2020-nhdpv2 2020 Census Block - NHDPlusV2 Catchment Intersections
3          epa_nrsa            EPA National Rivers and Streams Assessment
4    geoconnex-demo                     geoconnex contribution demo sites
5        gfv11_pois        USGS Geospatial Fabric V1.1 Points of Interest
6             GRAND                             Selected GRAND Reservoirs
                                                       features
1          https://api.water.usgs.gov/nldi/linked-data/ca_gages
2 https://api.water.usgs.gov/nldi/linked-data/census2020-nhdpv2
3          https://api.water.usgs.gov/nldi/linked-data/epa_nrsa
4    https://api.water.usgs.gov/nldi/linked-data/geoconnex-demo
5        https://api.water.usgs.gov/nldi/linked-data/gfv11_pois
6             https://api.water.usgs.gov/nldi/linked-data/grand
# Retrieve the NLDI record for a specific site
feature <- get_nldi_feature(nldi_feature)
feature
Simple feature collection with 1 feature and 8 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -89.36083 ymin: 43.08944 xmax: -89.36083 ymax: 43.08944
Geodetic CRS:  WGS 84
# A tibble: 1 × 9
  sourceName               identifier  comid name  reachcode measure     X     Y
  <chr>                    <chr>       <int> <chr> <chr>       <dbl> <dbl> <dbl>
1 NWIS Surface Water Sites USGS-0542… 1.33e7 YAHA… 07090002…    42.0 -89.4  43.1
# ℹ 1 more variable: geometry <POINT [°]>

See Navigation Modes for endpoint structure and mode descriptions.

nhdplusTools mode API mode Description
"UM" UM Upstream mainstem
"UT" UT Upstream with tributaries
"DM" DM Downstream mainstem
"DD" DD Downstream with diversions
# Navigate upstream with tributaries, collecting flowlines
flowlines <- navigate_nldi(
  nldi_feature,
  mode = "UT",
  data_source = "flowlines",
  distance_km = 100
)

nrow(flowlines)
NULL
head(flowlines)
$origin
Simple feature collection with 1 feature and 8 fields
Geometry type: POINT
Dimension:     XY
Bounding box:  xmin: -89.36083 ymin: 43.08944 xmax: -89.36083 ymax: 43.08944
Geodetic CRS:  WGS 84
# A tibble: 1 × 9
  sourceName               identifier  comid name  reachcode measure     X     Y
  <chr>                    <chr>       <int> <chr> <chr>       <dbl> <dbl> <dbl>
1 NWIS Surface Water Sites USGS-0542… 1.33e7 YAHA… 07090002…    42.0 -89.4  43.1
# ℹ 1 more variable: geometry <POINT [°]>

$UT_flowlines
Simple feature collection with 168 features and 1 field
Geometry type: LINESTRING
Dimension:     XY
Bounding box:  xmin: -89.58537 ymin: 43.08521 xmax: -89.21254 ymax: 43.30179
Geodetic CRS:  WGS 84
# A tibble: 168 × 2
   nhdplus_comid                                                        geometry
   <chr>                                                        <LINESTRING [°]>
 1 13293750      (-89.37037 43.09491, -89.36997 43.09475, -89.36916 43.09425, -…
 2 13294312      (-89.38441 43.09903, -89.38351 43.09872, -89.3824 43.09866, -8…
 3 13294308      (-89.37836 43.12705, -89.37849 43.12689, -89.38291 43.12426, -…
 4 13294310      (-89.41003 43.10678, -89.40898 43.10619, -89.40492 43.10585, -…
 5 13293634                              (-89.37711 43.1276, -89.37836 43.12705)
 6 13294304      (-89.42001 43.1326, -89.42044 43.13194, -89.42124 43.12364, -8…
 7 13294314      (-89.48229 43.10496, -89.48217 43.10476, -89.48196 43.10419, -…
 8 13294368                              (-89.37131 43.12712, -89.37711 43.1276)
 9 13294298      (-89.4151 43.145, -89.41507 43.14339, -89.41639 43.1413, -89.4…
10 13294300      (-89.43469 43.14222, -89.43362 43.14176, -89.43142 43.14151, -…
# ℹ 158 more rows
# Collect NWIS sites upstream
nwis_upstream <- navigate_nldi(
  nldi_feature,
  mode = "UT",
  data_source = "nwissite",
  distance_km = 100
)

nrow(nwis_upstream)
NULL

Basin

See Basin and Hydrolocation for algorithm details including the split-catchment workflow.

# Retrieve the upstream basin polygon (simplified by default)
basin <- get_nldi_basin(nldi_feature, simplify = TRUE)
basin
Simple feature collection with 1 feature and 0 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: -89.60465 ymin: 43.03507 xmax: -89.20378 ymax: 43.36607
Geodetic CRS:  WGS 84
# A tibble: 1 × 1
                                                                        geometry
                                                                   <POLYGON [°]>
1 ((-89.54456 43.06041, -89.5549 43.06299, -89.55518 43.06519, -89.5594 43.0695…

Choosing a Library

Task Recommended library
NLDI navigation + spatial analysis in Python PyNHD (HyRiver)
Quick feature discovery + NWIS data retrieval in R dataRetrieval
Granular NLDI control + network analysis in R nhdplusTools

For workflows combining spatial analysis with observational time series in R, dataRetrieval and nhdplusTools are often used together — dataRetrieval for discovering features and pulling discharge or water quality records, and nhdplusTools for network operations and catchment characteristics.


Notes & TODOs

  • TODO: Add Python-only code examples for navigate_byloc() — navigation starting from a coordinate rather than a known feature ID.
  • TODO: Add version pins or minimum version requirements once PyNHD API stability is confirmed for the Python NLDI endpoint.
  • TODO: Confirm feature_byloc() method name and signature in the current PyNHD release.
  • TODO: Cross-link from sibling pages (feature-sources.md, navigation.md, basin.md) back to this page once internal links are confirmed working.