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