This guide covers downloading water level data from USGS using the dataretrieval Python package. USGS maintains thousands of stream gages across the United States that record water levels at 15-minute intervals.
bash
pip install dataretrieval
The NWIS module is reliable and straightforward for accessing gage height data.
python
from dataretrieval import nwis
# Get instantaneous values (15-min intervals)
df, meta = nwis.get_iv(
sites='<station_id>',
start='<start_date>',
end='<end_date>',
parameterCd='00065'
)
# Get daily values
df, meta = nwis.get_dv(
sites='<station_id>',
start='<start_date>',
end='<end_date>',
parameterCd='00060'
)
# Get site information
info, meta = nwis.get_info(sites='<station_id>')
CodeParameterUnitDescription00065Gage heightfeetWater level above datum00060DischargecfsStreamflow volume
FunctionDescriptionData Frequencynwis.get_iv()Instantaneous values~15 minutesnwis.get_dv()Daily valuesDailynwis.get_info()Site informationN/Anwis.get_stats()Statistical summariesN/Anwis.get_peaks()Annual peak dischargeAnnual
The DataFrame has a datetime index and these columns:
ColumnDescriptionsite_noStation ID00065Water level value00065_cdQuality code (can ignore)
python
from dataretrieval import nwis
station_ids = ['<id_1>', '<id_2>', '<id_3>']
all_data = {}
for site_id in station_ids:
try:
df, meta = nwis.get_iv(
sites=site_id,
start='<start_date>',
end='<end_date>',
parameterCd='00065'
)
if len(df) > 0:
all_data[site_id] = df
except Exception as e:
print(f"Failed to download {site_id}: {e}")
print(f"Successfully downloaded: {len(all_data)} stations")
python
# Find the gage height column (excludes quality code column)
gage_col = [c for c in df.columns if '00065' in str(c) and '_cd' not in str(c)]
if gage_col:
water_levels = df[gage_col[0]]
print(water_levels.head())
IssueCauseSolutionEmpty DataFrameStation has no data for date rangeTry different dates or use get_iv()``get_dv() returns emptyNo daily gage height dataUse get_iv() and aggregateConnection errorNetwork issueWrap in try/except, retryRate limitedToo many requestsAdd delays between requests
len(df) > 0 before processingget_iv() for gage height, as daily data is often unavailable_cd)