USGS dataretrieval Python Package get_samples() Examples
This notebook provides examples of using the Python dataretrieval package to retrieve water quality sample data for United States Geological Survey (USGS) monitoring locations. The dataretrieval package provides a collection of functions to get data from the USGS Samples database and other online sources of hydrology and water quality data, including the United States Environmental Protection Agency (USEPA).
Install the Package
Use the following code to install the package if it doesn’t exist already within your Jupyter Python environment.
[1]:
!pip install dataretrieval
Requirement already satisfied: dataretrieval in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (0.1.dev1+gb3675aabc)
Requirement already satisfied: httpx in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from dataretrieval) (0.28.1)
Requirement already satisfied: pandas<4.0.0,>=2.0.0 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from dataretrieval) (3.0.6)
Requirement already satisfied: anyio>=4.0 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from dataretrieval) (4.15.1)
Requirement already satisfied: numpy>=1.26.0 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from pandas<4.0.0,>=2.0.0->dataretrieval) (2.5.3)
Requirement already satisfied: python-dateutil>=2.8.2 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from pandas<4.0.0,>=2.0.0->dataretrieval) (2.9.0.post0)
Requirement already satisfied: idna>=2.8 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from anyio>=4.0->dataretrieval) (3.20)
Requirement already satisfied: typing_extensions>=4.16.0 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from anyio>=4.0->dataretrieval) (4.16.0)
Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from python-dateutil>=2.8.2->pandas<4.0.0,>=2.0.0->dataretrieval) (1.17.0)
Requirement already satisfied: certifi in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from httpx->dataretrieval) (2026.7.22)
Requirement already satisfied: httpcore==1.* in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from httpx->dataretrieval) (1.0.9)
Requirement already satisfied: h11>=0.16 in /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages (from httpcore==1.*->httpx->dataretrieval) (0.16.0)
Load the package so you can use it along with other packages used in this notebook.
[2]:
from IPython.display import display
from dataretrieval import waterdata
Basic Usage
The dataretrieval package has several functions that allow you to retrieve data from different web services. This example uses the get_samples() function to retrieve water quality sample data for USGS monitoring locations from Samples. The allowable values for the categorical arguments below come from waterdata.get_codes() (see the Discrete water-quality samples notebook). The following arguments are supported:
ssl_check : boolean, optional Check the SSL certificate.
service : string One of the available Samples services: “results”, “locations”, “activities”, “projects”, or “organizations”. Defaults to “results”.
profile : string One of the available profiles associated with a service. Options for each service are: results - “fullphyschem”, “basicphyschem”, “fullbio”, “basicbio”, “narrow”, “resultdetectionquantitationlimit”, “labsampleprep”, “count” locations - “site”, “count” activities - “sampact”, “actmetric”, “actgroup”, “count” projects - “project”, “projectmonitoringlocationweight” organizations - “organization”, “count”
activityMediaName : string or list of strings, optional Name or code indicating environmental medium in which sample was taken. Use
get_codes(code_service="samplemedia")for all possible inputs. Example: “Water”.activityStartDateLower : string, optional The start date if using a date range. Takes the format YYYY-MM-DD. The logic is inclusive, i.e. it will also return results that match the date. If left as None, will pull all data on or before activityStartDateUpper, if populated.
activityStartDateUpper : string, optional The end date if using a date range. Takes the format YYYY-MM-DD. The logic is inclusive, i.e. it will also return results that match the date. If left as None, will pull all data after activityStartDateLower up to the most recent available results.
activityTypeCode : string or list of strings, optional Text code that describes type of field activity performed. Example: “Sample-Routine, regular”.
characteristicGroup : string or list of strings, optional Characteristic group is a broad category of characteristics describing one or more results. Use
get_codes(code_service="characteristicgroup")for all possible inputs. Example: “Organics, PFAS”characteristic : string or list of strings, optional Characteristic is a specific category describing one or more results. Use
get_codes(code_service="characteristics")for all possible inputs. Example: “Suspended Sediment Discharge”characteristicUserSupplied : string or list of strings, optional A user supplied characteristic name describing one or more results. Use
get_codes(code_service="observedproperty")for all possible inputs.boundingBox: list of four floats, optional Filters on the associated monitoring location’s point location by checking if it is located within the specified geographic area. The logic is inclusive, i.e. it will include locations that overlap with the edge of the bounding box. Values are separated by commas, expressed in decimal degrees, NAD83, and longitudes west of Greenwich are negative. The format is a string consisting of: - Western-most longitude - Southern-most latitude - Eastern-most longitude - Northern-most longitude Example: [-92.8,44.2,-88.9,46.0]
countryFips : string or list of strings, optional Example: “US” (United States)
stateFips : string or list of strings, optional Example: “US:15” (United States: Hawaii)
countyFips : string or list of strings, optional Example: “US:15:001” (United States: Hawaii, Hawaii County)
siteTypeCode : string or list of strings, optional An abbreviation for a certain site type. Use
get_codes(code_service="sitetype")for all possible inputs. Example: “GW” (Groundwater site)siteTypeName : string or list of strings, optional A full name for a certain site type. Use
get_codes(code_service="sitetype")for all possible inputs. Example: “Well”usgsPCode : string or list of strings, optional 5-digit number used in the US Geological Survey computerized data system, National Water Information System (NWIS), to uniquely identify a specific constituent. Use
get_codes(code_service="characteristics")for all possible inputs. Example: “00060” (Discharge, cubic feet per second)hydrologicUnit : string or list of strings, optional Max 12-digit number used to describe a hydrologic unit. Example: “070900020502”
monitoringLocationIdentifier : string or list of strings, optional A monitoring location identifier has two parts: the agency code and the location number, separated by a dash (-). Example: “USGS-040851385”
organizationIdentifier : string or list of strings, optional Designator used to uniquely identify a specific organization. Currently only accepting the organization “USGS”.
pointLocationLatitude : float, optional Latitude for a point/radius query (decimal degrees). Must be used with pointLocationLongitude and pointLocationWithinMiles.
pointLocationLongitude : float, optional Longitude for a point/radius query (decimal degrees). Must be used with pointLocationLatitude and pointLocationWithinMiles.
pointLocationWithinMiles : float, optional Radius for a point/radius query. Must be used with pointLocationLatitude and pointLocationLongitude
projectIdentifier : string or list of strings, optional Designator used to uniquely identify a data collection project. Project identifiers are specific to an organization (e.g. USGS). Example: “ZH003QW03”
recordIdentifierUserSupplied : string or list of strings, optional Internal AQS record identifier that returns 1 entry. Only available for the “results” service.
Example 1: Get all water quality sample data for a single monitoring site
[3]:
siteID = "USGS-10109000"
wq_data = waterdata.get_samples(monitoringLocationIdentifier=siteID)
print("Retrieved data for " + str(len(wq_data[0])) + " samples.")
/tmp/ipykernel_5438/2642924150.py:2: DeprecationWarning: The 'monitoringLocationIdentifier' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'monitoring_location_id' instead.
wq_data = waterdata.get_samples(monitoringLocationIdentifier=siteID)
---------------------------------------------------------------------------
ReadTimeout Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:101, in map_httpcore_exceptions()
100 try:
--> 101 yield
102 except Exception as exc:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:250, in HTTPTransport.handle_request(self, request)
249 with map_httpcore_exceptions():
--> 250 resp = self._pool.handle_request(req)
252 assert isinstance(resp.stream, typing.Iterable)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/connection_pool.py:256, in ConnectionPool.handle_request(self, request)
255 self._close_connections(closing)
--> 256 raise exc from None
258 # Return the response. Note that in this case we still have to manage
259 # the point at which the response is closed.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/connection_pool.py:236, in ConnectionPool.handle_request(self, request)
234 try:
235 # Send the request on the assigned connection.
--> 236 response = connection.handle_request(
237 pool_request.request
238 )
239 except ConnectionNotAvailable:
240 # In some cases a connection may initially be available to
241 # handle a request, but then become unavailable.
242 #
243 # In this case we clear the connection and try again.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/connection.py:103, in HTTPConnection.handle_request(self, request)
101 raise exc
--> 103 return self._connection.handle_request(request)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:136, in HTTP11Connection.handle_request(self, request)
135 self._response_closed()
--> 136 raise exc
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:106, in HTTP11Connection.handle_request(self, request)
97 with Trace(
98 "receive_response_headers", logger, request, kwargs
99 ) as trace:
100 (
101 http_version,
102 status,
103 reason_phrase,
104 headers,
105 trailing_data,
--> 106 ) = self._receive_response_headers(**kwargs)
107 trace.return_value = (
108 http_version,
109 status,
110 reason_phrase,
111 headers,
112 )
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:177, in HTTP11Connection._receive_response_headers(self, request)
176 while True:
--> 177 event = self._receive_event(timeout=timeout)
178 if isinstance(event, h11.Response):
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:217, in HTTP11Connection._receive_event(self, timeout)
216 if event is h11.NEED_DATA:
--> 217 data = self._network_stream.read(
218 self.READ_NUM_BYTES, timeout=timeout
219 )
221 # If we feed this case through h11 we'll raise an exception like:
222 #
223 # httpcore.RemoteProtocolError: can't handle event type
(...) 227 # perspective. Instead we handle this case distinctly and treat
228 # it as a ConnectError.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_backends/sync.py:126, in SyncStream.read(self, max_bytes, timeout)
125 exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError}
--> 126 with map_exceptions(exc_map):
127 self._sock.settimeout(timeout)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/contextlib.py:162, in _GeneratorContextManager.__exit__(self, typ, value, traceback)
161 try:
--> 162 self.gen.throw(value)
163 except StopIteration as exc:
164 # Suppress StopIteration *unless* it's the same exception that
165 # was passed to throw(). This prevents a StopIteration
166 # raised inside the "with" statement from being suppressed.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_exceptions.py:14, in map_exceptions(map)
13 if isinstance(exc, from_exc):
---> 14 raise to_exc(exc) from exc
15 raise
ReadTimeout: The read operation timed out
The above exception was the direct cause of the following exception:
ReadTimeout Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/transport/http.py:96, in get(url, **kwargs)
95 with httpx.Client(**client_options) as client:
---> 96 return client.get(url, **kwargs)
97 except httpx.TransportError as exc:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:1053, in Client.get(self, url, params, headers, cookies, auth, follow_redirects, timeout, extensions)
1048 """
1049 Send a `GET` request.
1050
1051 **Parameters**: See `httpx.request`.
1052 """
-> 1053 return self.request(
1054 "GET",
1055 url,
1056 params=params,
1057 headers=headers,
1058 cookies=cookies,
1059 auth=auth,
1060 follow_redirects=follow_redirects,
1061 timeout=timeout,
1062 extensions=extensions,
1063 )
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:825, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
812 request = self.build_request(
813 method=method,
814 url=url,
(...) 823 extensions=extensions,
824 )
--> 825 return self.send(request, auth=auth, follow_redirects=follow_redirects)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:914, in Client.send(self, request, stream, auth, follow_redirects)
912 auth = self._build_request_auth(request, auth)
--> 914 response = self._send_handling_auth(
915 request,
916 auth=auth,
917 follow_redirects=follow_redirects,
918 history=[],
919 )
920 try:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:942, in Client._send_handling_auth(self, request, auth, follow_redirects, history)
941 while True:
--> 942 response = self._send_handling_redirects(
943 request,
944 follow_redirects=follow_redirects,
945 history=history,
946 )
947 try:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:979, in Client._send_handling_redirects(self, request, follow_redirects, history)
977 hook(request)
--> 979 response = self._send_single_request(request)
980 try:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:1014, in Client._send_single_request(self, request)
1013 with request_context(request=request):
-> 1014 response = transport.handle_request(request)
1016 assert isinstance(response.stream, SyncByteStream)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:249, in HTTPTransport.handle_request(self, request)
237 req = httpcore.Request(
238 method=request.method,
239 url=httpcore.URL(
(...) 247 extensions=request.extensions,
248 )
--> 249 with map_httpcore_exceptions():
250 resp = self._pool.handle_request(req)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/contextlib.py:162, in _GeneratorContextManager.__exit__(self, typ, value, traceback)
161 try:
--> 162 self.gen.throw(value)
163 except StopIteration as exc:
164 # Suppress StopIteration *unless* it's the same exception that
165 # was passed to throw(). This prevents a StopIteration
166 # raised inside the "with" statement from being suppressed.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:118, in map_httpcore_exceptions()
117 message = str(exc)
--> 118 raise mapped_exc(message) from exc
ReadTimeout: The read operation timed out
The above exception was the direct cause of the following exception:
NetworkError Traceback (most recent call last)
Cell In[3], line 2
1 siteID = "USGS-10109000"
----> 2 wq_data = waterdata.get_samples(monitoringLocationIdentifier=siteID)
3 print("Retrieved data for " + str(len(wq_data[0])) + " samples.")
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/waterdata/utils.py:348, in _accept_legacy_kwargs.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
340 warn_deprecated(
341 f"The {old_name!r} argument",
342 replacement=repr(new_name),
(...) 345 stacklevel=2,
346 )
347 kwargs[new_name] = kwargs.pop(old_name)
--> 348 return func(*args, **kwargs)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/waterdata/samples.py:369, in get_samples(ssl_check, service, profile, activity_media_name, activity_start_date_lower, activity_start_date_upper, activity_type_code, characteristic_group, characteristic, characteristic_user_supplied, bbox, country_code, state_code, county_code, site_type_code, site_type_name, usgs_pcode, hydrologic_unit, monitoring_location_id, organization_id, point_location_latitude, point_location_longitude, point_location_within_miles, project_id, record_identifier_user_supplied)
365 params["boundingBox"] = to_str(params["boundingBox"])
367 url = f"{samples_url()}/{service}/{profile}"
--> 369 df, response = _get_samples_csv(url, params, ssl_check)
370 df = _attach_datetime_columns(df)
372 return df, BaseMetadata(response)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/waterdata/samples.py:95, in _get_samples_csv(url, params, ssl_check)
86 """Issue a Samples CSV request and parse the body into a DataFrame.
87
88 Shared final step for the Samples getters: sends the GET with the standard
(...) 92 as metadata and applies any per-getter post-step.
93 """
94 logger.debug("Request: %s", httpx.URL(url).copy_merge_params(params))
---> 95 response = _get(
96 url,
97 params=params,
98 verify=ssl_check,
99 headers=_default_headers(url),
100 **HTTPX_DEFAULTS,
101 )
102 _raise_for_non_200(response)
103 df = read_code_csv(response.text)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/transport/http.py:98, in get(url, **kwargs)
96 return client.get(url, **kwargs)
97 except httpx.TransportError as exc:
---> 98 raise network_error(url, exc) from exc
NetworkError: Could not reach the service at https://api.waterdata.usgs.gov/samples-data/results/fullphyschem: The read operation timed out
Interpreting the Result
The result of calling the get_samples() function is an object that contains a Pandas data frame object and an associated metadata object. The Pandas data frame contains the water quality sample data for the requested monitoring location, observed variables, and time frame.
Once you’ve got the data frame, there are several useful things you can do to explore the data.
Display the data frame as a table. The default data frame for this function is a long, flat table, with a row for each observed variable at a given monitoring location and date/time.
[4]:
display(wq_data[0])
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[4], line 1
----> 1 display(wq_data[0])
NameError: name 'wq_data' is not defined
Show the data types of the columns in the resulting data frame.
[5]:
print(wq_data[0].dtypes)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[5], line 1
----> 1 print(wq_data[0].dtypes)
NameError: name 'wq_data' is not defined
The other part of the result returned from the get_samples() function is a metadata object that contains information about the query that was executed to return the data. For example, you can access the URL that was assembled to retrieve the requested data from the USGS Water Data API.
[6]:
print(
"The query URL used to retrieve the data from USGS Samples was: " + wq_data[1].url
)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[6], line 2
1 print(
----> 2 "The query URL used to retrieve the data from USGS Samples was: " + wq_data[1].url
3 )
NameError: name 'wq_data' is not defined
Additional Examples
Example 2: Get water quality sample data for multiple sites for a single parameter
[7]:
site_ids = ["USGS-04024430", "USGS-04024000"]
parameter_code = "00065"
wq_multi_site = waterdata.get_samples(
monitoringLocationIdentifier=site_ids, usgsPCode=parameter_code
)
print("Retrieved data for " + str(len(wq_multi_site[0])) + " samples.")
display(wq_multi_site[0])
/tmp/ipykernel_5438/3910379390.py:3: DeprecationWarning: The 'usgsPCode' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'usgs_pcode' instead.
wq_multi_site = waterdata.get_samples(
/tmp/ipykernel_5438/3910379390.py:3: DeprecationWarning: The 'monitoringLocationIdentifier' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'monitoring_location_id' instead.
wq_multi_site = waterdata.get_samples(
---------------------------------------------------------------------------
ReadTimeout Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:101, in map_httpcore_exceptions()
100 try:
--> 101 yield
102 except Exception as exc:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:250, in HTTPTransport.handle_request(self, request)
249 with map_httpcore_exceptions():
--> 250 resp = self._pool.handle_request(req)
252 assert isinstance(resp.stream, typing.Iterable)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/connection_pool.py:256, in ConnectionPool.handle_request(self, request)
255 self._close_connections(closing)
--> 256 raise exc from None
258 # Return the response. Note that in this case we still have to manage
259 # the point at which the response is closed.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/connection_pool.py:236, in ConnectionPool.handle_request(self, request)
234 try:
235 # Send the request on the assigned connection.
--> 236 response = connection.handle_request(
237 pool_request.request
238 )
239 except ConnectionNotAvailable:
240 # In some cases a connection may initially be available to
241 # handle a request, but then become unavailable.
242 #
243 # In this case we clear the connection and try again.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/connection.py:103, in HTTPConnection.handle_request(self, request)
101 raise exc
--> 103 return self._connection.handle_request(request)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:136, in HTTP11Connection.handle_request(self, request)
135 self._response_closed()
--> 136 raise exc
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:106, in HTTP11Connection.handle_request(self, request)
97 with Trace(
98 "receive_response_headers", logger, request, kwargs
99 ) as trace:
100 (
101 http_version,
102 status,
103 reason_phrase,
104 headers,
105 trailing_data,
--> 106 ) = self._receive_response_headers(**kwargs)
107 trace.return_value = (
108 http_version,
109 status,
110 reason_phrase,
111 headers,
112 )
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:177, in HTTP11Connection._receive_response_headers(self, request)
176 while True:
--> 177 event = self._receive_event(timeout=timeout)
178 if isinstance(event, h11.Response):
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_sync/http11.py:217, in HTTP11Connection._receive_event(self, timeout)
216 if event is h11.NEED_DATA:
--> 217 data = self._network_stream.read(
218 self.READ_NUM_BYTES, timeout=timeout
219 )
221 # If we feed this case through h11 we'll raise an exception like:
222 #
223 # httpcore.RemoteProtocolError: can't handle event type
(...) 227 # perspective. Instead we handle this case distinctly and treat
228 # it as a ConnectError.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_backends/sync.py:126, in SyncStream.read(self, max_bytes, timeout)
125 exc_map: ExceptionMapping = {socket.timeout: ReadTimeout, OSError: ReadError}
--> 126 with map_exceptions(exc_map):
127 self._sock.settimeout(timeout)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/contextlib.py:162, in _GeneratorContextManager.__exit__(self, typ, value, traceback)
161 try:
--> 162 self.gen.throw(value)
163 except StopIteration as exc:
164 # Suppress StopIteration *unless* it's the same exception that
165 # was passed to throw(). This prevents a StopIteration
166 # raised inside the "with" statement from being suppressed.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpcore/_exceptions.py:14, in map_exceptions(map)
13 if isinstance(exc, from_exc):
---> 14 raise to_exc(exc) from exc
15 raise
ReadTimeout: The read operation timed out
The above exception was the direct cause of the following exception:
ReadTimeout Traceback (most recent call last)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/transport/http.py:96, in get(url, **kwargs)
95 with httpx.Client(**client_options) as client:
---> 96 return client.get(url, **kwargs)
97 except httpx.TransportError as exc:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:1053, in Client.get(self, url, params, headers, cookies, auth, follow_redirects, timeout, extensions)
1048 """
1049 Send a `GET` request.
1050
1051 **Parameters**: See `httpx.request`.
1052 """
-> 1053 return self.request(
1054 "GET",
1055 url,
1056 params=params,
1057 headers=headers,
1058 cookies=cookies,
1059 auth=auth,
1060 follow_redirects=follow_redirects,
1061 timeout=timeout,
1062 extensions=extensions,
1063 )
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:825, in Client.request(self, method, url, content, data, files, json, params, headers, cookies, auth, follow_redirects, timeout, extensions)
812 request = self.build_request(
813 method=method,
814 url=url,
(...) 823 extensions=extensions,
824 )
--> 825 return self.send(request, auth=auth, follow_redirects=follow_redirects)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:914, in Client.send(self, request, stream, auth, follow_redirects)
912 auth = self._build_request_auth(request, auth)
--> 914 response = self._send_handling_auth(
915 request,
916 auth=auth,
917 follow_redirects=follow_redirects,
918 history=[],
919 )
920 try:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:942, in Client._send_handling_auth(self, request, auth, follow_redirects, history)
941 while True:
--> 942 response = self._send_handling_redirects(
943 request,
944 follow_redirects=follow_redirects,
945 history=history,
946 )
947 try:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:979, in Client._send_handling_redirects(self, request, follow_redirects, history)
977 hook(request)
--> 979 response = self._send_single_request(request)
980 try:
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_client.py:1014, in Client._send_single_request(self, request)
1013 with request_context(request=request):
-> 1014 response = transport.handle_request(request)
1016 assert isinstance(response.stream, SyncByteStream)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:249, in HTTPTransport.handle_request(self, request)
237 req = httpcore.Request(
238 method=request.method,
239 url=httpcore.URL(
(...) 247 extensions=request.extensions,
248 )
--> 249 with map_httpcore_exceptions():
250 resp = self._pool.handle_request(req)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/contextlib.py:162, in _GeneratorContextManager.__exit__(self, typ, value, traceback)
161 try:
--> 162 self.gen.throw(value)
163 except StopIteration as exc:
164 # Suppress StopIteration *unless* it's the same exception that
165 # was passed to throw(). This prevents a StopIteration
166 # raised inside the "with" statement from being suppressed.
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/httpx/_transports/default.py:118, in map_httpcore_exceptions()
117 message = str(exc)
--> 118 raise mapped_exc(message) from exc
ReadTimeout: The read operation timed out
The above exception was the direct cause of the following exception:
NetworkError Traceback (most recent call last)
Cell In[7], line 3
1 site_ids = ["USGS-04024430", "USGS-04024000"]
2 parameter_code = "00065"
----> 3 wq_multi_site = waterdata.get_samples(
4 monitoringLocationIdentifier=site_ids, usgsPCode=parameter_code
5 )
6 print("Retrieved data for " + str(len(wq_multi_site[0])) + " samples.")
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/waterdata/utils.py:348, in _accept_legacy_kwargs.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
340 warn_deprecated(
341 f"The {old_name!r} argument",
342 replacement=repr(new_name),
(...) 345 stacklevel=2,
346 )
347 kwargs[new_name] = kwargs.pop(old_name)
--> 348 return func(*args, **kwargs)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/waterdata/samples.py:369, in get_samples(ssl_check, service, profile, activity_media_name, activity_start_date_lower, activity_start_date_upper, activity_type_code, characteristic_group, characteristic, characteristic_user_supplied, bbox, country_code, state_code, county_code, site_type_code, site_type_name, usgs_pcode, hydrologic_unit, monitoring_location_id, organization_id, point_location_latitude, point_location_longitude, point_location_within_miles, project_id, record_identifier_user_supplied)
365 params["boundingBox"] = to_str(params["boundingBox"])
367 url = f"{samples_url()}/{service}/{profile}"
--> 369 df, response = _get_samples_csv(url, params, ssl_check)
370 df = _attach_datetime_columns(df)
372 return df, BaseMetadata(response)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/waterdata/samples.py:95, in _get_samples_csv(url, params, ssl_check)
86 """Issue a Samples CSV request and parse the body into a DataFrame.
87
88 Shared final step for the Samples getters: sends the GET with the standard
(...) 92 as metadata and applies any per-getter post-step.
93 """
94 logger.debug("Request: %s", httpx.URL(url).copy_merge_params(params))
---> 95 response = _get(
96 url,
97 params=params,
98 verify=ssl_check,
99 headers=_default_headers(url),
100 **HTTPX_DEFAULTS,
101 )
102 _raise_for_non_200(response)
103 df = read_code_csv(response.text)
File /opt/hostedtoolcache/Python/3.13.15/x64/lib/python3.13/site-packages/dataretrieval/transport/http.py:98, in get(url, **kwargs)
96 return client.get(url, **kwargs)
97 except httpx.TransportError as exc:
---> 98 raise network_error(url, exc) from exc
NetworkError: Could not reach the service at https://api.waterdata.usgs.gov/samples-data/results/fullphyschem: The read operation timed out
Example 3: Retrieve water quality sample data for multiple sites, including a list of parameters, within a time period defined by start date until present
[8]:
site_ids = ["USGS-04024430", "USGS-04024000"]
parameterCd = ["34247", "30234", "32104", "34220"]
startDate = "2012-01-01"
wq_data2 = waterdata.get_samples(
monitoringLocationIdentifier=site_ids,
usgsPCode=parameterCd,
activityStartDateLower=startDate,
)
print("Retrieved data for " + str(len(wq_data2[0])) + " samples.")
display(wq_data2[0])
/tmp/ipykernel_5438/2201109112.py:4: DeprecationWarning: The 'activityStartDateLower' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'activity_start_date_lower' instead.
wq_data2 = waterdata.get_samples(
/tmp/ipykernel_5438/2201109112.py:4: DeprecationWarning: The 'usgsPCode' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'usgs_pcode' instead.
wq_data2 = waterdata.get_samples(
/tmp/ipykernel_5438/2201109112.py:4: DeprecationWarning: The 'monitoringLocationIdentifier' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'monitoring_location_id' instead.
wq_data2 = waterdata.get_samples(
Retrieved data for 152 samples.
| Org_Identifier | Org_FormalName | Project_Identifier | Project_Name | Project_QAPPApproved | Project_QAPPApprovalAgency | ProjectAttachment_FileName | ProjectAttachment_FileType | Location_Identifier | Location_Name | ... | Org_Type | LastChangeDate | USGSpcode | USGSSampleAquifer | Activity_StartDateTime | Activity_EndDateTime | LabInfo_AnalysisStartDateTime | LabInfo_AnalysisEndDateTime | LabSamplePrepMethod_StartDateTime | LabSamplePrepMethod_EndDateTime | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","GR12NK0... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 32104 | NaN | 2012-01-25 14:40:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 1 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","GR12NK0... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 30234 | NaN | 2012-01-25 14:40:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 2 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","GR12NK0... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-20 | 34247 | NaN | 2012-01-25 14:40:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 3 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","GR12NK0... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-20 | 34220 | NaN | 2012-01-25 14:40:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 4 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","GR12NK0... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 32104 | NaN | 2012-02-22 14:45:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 147 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","00GQ414... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 34220 | NaN | 2018-05-01 16:05:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 148 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","00GQ414... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 34220 | NaN | 2018-07-09 16:25:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 149 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","00GQ414... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 32104 | NaN | 2018-07-09 16:25:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 150 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","00GQ414... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-21 | 30234 | NaN | 2018-07-09 16:25:00+00:00 | NaT | NaT | NaT | NaT | NaT |
| 151 | USGS | U.S. Geological Survey | ["Great Lakes Restoration Initiative","00GQ414... | NaN | NaN | NaN | NaN | NaN | USGS-04024000 | ST. LOUIS RIVER AT SCANLON, MN | ... | Federal/US Government | 2026-07-20 | 34247 | NaN | 2018-07-09 16:25:00+00:00 | NaT | NaT | NaT | NaT | NaT |
152 rows × 187 columns
Example 4: Retrieve water quality sample data for one site and convert to a wide format
Note that the USGS Samples database returns multiple parameters in a “long” format: each row in the resulting table represents a single observation of a single parameter. Furthermore, every observation comes with more than 180 fields of metadata (the default fullphyschem profile returns 187 columns). However, if you wanted to place your water quality data into a “wide” format, where each column represents a water quality parameter code, the code below details one solution.
[9]:
siteID = "USGS-10109000"
wq_data, _ = waterdata.get_samples(monitoringLocationIdentifier=siteID)
print("Retrieved data for " + str(len(wq_data)) + " sample results.")
wq_data["characteristic_unit"] = (
wq_data["Result_Characteristic"] + ", " + wq_data["Result_MeasureUnit"]
)
wq_data_wide = wq_data.pivot_table(
index=["Location_Identifier", "Activity_StartDate", "Activity_StartTime"],
columns="characteristic_unit",
values="Result_Measure",
aggfunc="first",
)
display(wq_data_wide)
/tmp/ipykernel_5438/1863275440.py:2: DeprecationWarning: The 'monitoringLocationIdentifier' argument is deprecated and will be removed from `dataretrieval` in a future release; use 'monitoring_location_id' instead.
wq_data, _ = waterdata.get_samples(monitoringLocationIdentifier=siteID)
Retrieved data for 2434 sample results.
/tmp/ipykernel_5438/1863275440.py:5: PerformanceWarning: DataFrame is highly fragmented. This is usually the result of calling `frame.insert` many times, which has poor performance. Consider joining all columns at once using pd.concat(axis=1) instead. To get a de-fragmented frame, use `newframe = frame.copy()`
wq_data["characteristic_unit"] = (
| characteristic_unit | Acidity, (H+), mg/L | Alkalinity, mg/L | Bicarbonate, mg/L | Calcium, mg/L | Carbon dioxide, mg/L | Carbonate, mg/L | Chloride, mg/L | Depth of water column, ft | Hardness, Ca, Mg, mg/L | Hardness, non-carbonate, mg/L | ... | Stream flow, instantaneous, m3/sec | Stream flow, m3/sec | Stream width measure, ft | Sulfate, mg/L | Temperature, air, deg C | Temperature, water, deg C | Total dissolved solids, mg/L | Total dissolved solids, tons/ac ft | Total dissolved solids, tons/day | pH, standard units | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Location_Identifier | Activity_StartDate | Activity_StartTime | |||||||||||||||||||||
| USGS-10109000 | 1967-09-13 | 07:35:00 | 0.00001 | 187 | 228 | 44.0 | 2.9 | 0.0 | 3.5 | NaN | 190 | 0.0 | ... | NaN | 5.8 | NaN | 6.5 | NaN | 7.0 | 196 | 0.27 | 108 | 8.1 |
| 1968-01-18 | 12:20:00 | 0.00002 | 207 | 252 | 52.0 | 6.5 | 0.0 | 3.9 | NaN | 220 | 17 | ... | NaN | 3.2 | NaN | 17.0 | NaN | 4.0 | 210 | 0.29 | 63.5 | 7.8 | |
| 1968-05-15 | 12:30:00 | 0.00004 | 149 | 182 | 38.0 | 12 | 0.0 | 1.7 | NaN | 150 | 0.0 | ... | NaN | 10 | NaN | 5.5 | NaN | 7.0 | 156 | 0.21 | 151 | 7.4 | |
| 1968-07-26 | 14:40:00 | 0.00002 | 179 | 218 | 53.0 | 7.0 | 0.0 | 2.2 | NaN | 180 | 3 | ... | NaN | 7.5 | NaN | 6.2 | NaN | 12.0 | 188 | 0.26 | 135 | 7.7 | |
| 1972-12-08 | 16:15:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 4.0 | NaN | NaN | NaN | NaN | 3.0 | NaN | NaN | NaN | NaN | |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | |
| 2026-05-12 | 13:46:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 10 | NaN | 51.9 | NaN | NaN | 10.4 | NaN | NaN | NaN | NaN | |
| 2026-05-26 | 17:23:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 9.1 | NaN | 51.2 | NaN | NaN | 11.6 | NaN | NaN | NaN | NaN | |
| 2026-07-08 | 10:44:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 3.0 | NaN | 46.0 | NaN | NaN | 12.5 | NaN | NaN | NaN | NaN | |
| 2026-08-12 | 10:13:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.9 | NaN | 48.0 | NaN | NaN | 13.3 | NaN | NaN | NaN | NaN | |
| 2026-09-08 | 16:22:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.9 | NaN | 45.0 | NaN | NaN | 13.2 | NaN | NaN | NaN | NaN |
360 rows × 34 columns