From 786e811028ad0b5c853da3d88bda5d5ef397df66 Mon Sep 17 00:00:00 2001 From: Pabitra Dash Date: Sun, 28 Apr 2024 12:07:42 -0400 Subject: [PATCH] [#135] NLDI data retrieval (#136) * [#135] initial implementation of NLDI data access * [#135] adding additional NLDI data access functionality * [#135] convert boolean type query parameters to string type * [#135] setting default distance to 5 kms for flowlines * [#135] tests for NLDI data access * Set NLDI optional dependency * Fix python-package.yml * Rollback geopandas for Python 3.8 * Throw warning to install geopandas --------- Co-authored-by: thodson --- .github/workflows/python-package.yml | 47 +- .github/workflows/sphinx-docs.yml | 49 +- dataretrieval/nldi.py | 495 +++++++++++ pyproject.toml | 14 +- requirements-dev.txt | 1 + requirements.txt | 4 - tests/data/nldi_get_basin.json | 138 ++++ tests/data/nldi_get_features_by_comid.json | 770 ++++++++++++++++++ ...tures_by_feature_source_with_nav_mode.json | 185 +++++ ...es_by_feature_source_without_nav_mode.json | 23 + tests/data/nldi_get_features_by_lat_long.json | 47 ++ tests/data/nldi_get_flowlines.json | 43 + tests/data/nldi_get_flowlines_by_comid.json | 285 +++++++ tests/nldi_test.py | 278 +++++++ 14 files changed, 2323 insertions(+), 56 deletions(-) create mode 100644 dataretrieval/nldi.py delete mode 100755 requirements.txt create mode 100644 tests/data/nldi_get_basin.json create mode 100644 tests/data/nldi_get_features_by_comid.json create mode 100644 tests/data/nldi_get_features_by_feature_source_with_nav_mode.json create mode 100644 tests/data/nldi_get_features_by_feature_source_without_nav_mode.json create mode 100644 tests/data/nldi_get_features_by_lat_long.json create mode 100644 tests/data/nldi_get_flowlines.json create mode 100644 tests/data/nldi_get_flowlines_by_comid.json create mode 100644 tests/nldi_test.py diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 03087c1..d3b6399 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -9,33 +9,32 @@ on: jobs: build: - runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: [3.8, 3.9, '3.10'] + os: [ubuntu-latest, windows-latest] + python-version: [3.8, 3.9, '3.10', 3.11] steps: - - uses: actions/checkout@v2 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements-dev.txt - - name: Lint with flake8 - run: | - # stop the build if there are Python syntax errors or undefined names - flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - - name: Test with pytest and report coverage - run: | - cd tests - coverage run -m pytest - coverage report -m - cd .. + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install .[test,nldi] + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest and report coverage + run: | + cd tests + coverage run -m pytest + coverage report -m + cd .. diff --git a/.github/workflows/sphinx-docs.yml b/.github/workflows/sphinx-docs.yml index eccdb27..8292e76 100644 --- a/.github/workflows/sphinx-docs.yml +++ b/.github/workflows/sphinx-docs.yml @@ -10,32 +10,31 @@ jobs: docs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 - with: - persist-credentials: false - - name: Install dataretrieval, dependencies, and Sphinx then build docs - shell: bash -l {0} - run: | - python -m pip install --upgrade pip - pip install -r requirements-dev.txt - pip install . - sudo apt update -y && sudo apt install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended dvipng pandoc - (cd docs && make docs) - (cd docs && make html) - - name: Debug - run: | - echo $REF - echo $EVENT_NAME - echo ${{ github.event_name == 'push' }} - echo ${{ github.ref == 'refs/heads/master' }} - echo ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - - name: Deploy to GitHub Pages - uses: JamesIves/github-pages-deploy-action@v4.4.1 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} - with: + - name: Checkout + uses: actions/checkout@v3 + with: + persist-credentials: false + - name: Install dataretrieval, dependencies, and Sphinx then build docs + shell: bash -l {0} + run: | + python -m pip install --upgrade pip + pip install .[doc] + sudo apt update -y && sudo apt install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended dvipng pandoc + (cd docs && make docs) + (cd docs && make html) + - name: Debug + run: | + echo $REF + echo $EVENT_NAME + echo ${{ github.event_name == 'push' }} + echo ${{ github.ref == 'refs/heads/master' }} + echo ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + - name: Deploy to GitHub Pages + uses: JamesIves/github-pages-deploy-action@v4.4.1 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} + with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} EVENT_NAME: ${{ github.event_name }} REF: ${{ github.ref }} BRANCH: gh-pages - FOLDER: docs/build/html \ No newline at end of file + FOLDER: docs/build/html diff --git a/dataretrieval/nldi.py b/dataretrieval/nldi.py new file mode 100644 index 0000000..4c850a2 --- /dev/null +++ b/dataretrieval/nldi.py @@ -0,0 +1,495 @@ +from json import JSONDecodeError +from typing import Literal, Optional, Union + +from dataretrieval.utils import query + +try: + import geopandas as gpd +except ImportError: + raise ImportError('Install geopandas to use the NLDI module.') + +NLDI_API_BASE_URL = 'https://labs.waterdata.usgs.gov/api/nldi/linked-data' +_AVAILABLE_DATA_SOURCES = None + + +def _query_nldi(url, query_params, error_message): + # A helper function to query the NLDI API + response = query(url, payload=query_params) + if response.status_code != 200: + raise ValueError(f'{error_message}. Error reason: {response.reason}') + + response_data = {} + try: + response_data = response.json() + except JSONDecodeError: + # even with a 200 status code, the response sometimes does not return JSON + # data which causes a JSONDecodeError + pass + return response_data + + +def get_flowlines( + navigation_mode: str, + distance: int = 5, + feature_source: Optional[str] = None, + feature_id: Optional[str] = None, + comid: Optional[int] = None, + stop_comid: Optional[int] = None, + trim_start: bool = False, + as_json: bool = False, +) -> Union[gpd.GeoDataFrame, dict]: + """Gets the flowlines for the specified navigation either by comid or feature + source in WGS84 lat/long coordinates as GeoDataFrame containing a polyline geometry. + + Parameters + ---------- + navigation_mode: string, navigation mode, allowed values are 'UM', 'DM', 'UT', 'DD' + distance: int, distance in kilometers, default is 5 + feature_source: string, optional, name of the feature source, + required if comid is not provided + feature_id: string, optional, identifier of the feature, + required if comid is not provided + comid: integer, optional, comid, required if feature source is not provided + stop_comid: integer, optional, stop comid + trim_start: bool, trim start, default is False + as_json: bool, optional, return flowlines as JSON if set to True, + otherwise return as GeoDataFrame, default is False + + Returns + ------- + gdf: GeoDataFrame or dict + GeoDataFrame/dict of flowlines + + Examples + -------- + .. doctest:: + + >>> # Get flowlines for a feature source: WQP and + >>> # feature id: USGS-01031500 in the upstream main + >>> gdf = dataretrieval.nldi.get_flowlines( + ... feature_source="WQP", feature_id="USGS-01031500", navigation_mode="UM" + ... ) + >>> # Get flowlines for comid: 13294314 in the upstream main + >>> gdf = dataretrieval.nldi.get_flowlines(comid=13294314, navigation_mode="UM") + """ + # validate the navigation mode + _validate_navigation_mode(navigation_mode) + # validate the feature source and comid + _validate_feature_source_comid(feature_source, feature_id, comid) + if feature_source: + # validate the feature source + _validate_data_source(feature_source) + + url = f'{NLDI_API_BASE_URL}/{feature_source}/{feature_id}/navigation' + query_params = {'distance': str(distance), 'trimStart': str(trim_start).lower()} + else: + url = f'{NLDI_API_BASE_URL}/comid/{comid}/navigation' + query_params = {'distance': str(distance)} + + url += f'/{navigation_mode}/flowlines' + if stop_comid is not None: + query_params['stopComid'] = str(stop_comid) + + if feature_source: + err_msg = ( + f"Error getting flowlines for feature source '{feature_source}'" + f" and feature_id '{feature_id}'" + ) + else: + err_msg = f"Error getting flowlines for comid '{comid}'" + + feature_collection = _query_nldi(url, query_params, err_msg) + if as_json: + return feature_collection + gdf = gpd.GeoDataFrame.from_features(feature_collection) + return gdf + + +def get_basin( + feature_source: str, + feature_id: str, + simplified: bool = True, + split_catchment: bool = False, + as_json: bool = False, +) -> Union[gpd.GeoDataFrame, dict]: + """Gets the aggregated basin for the specified feature in WGS84 lat/lon + as GeoDataFrame or as JSON conatining a polygon geometry. + + Parameters + ---------- + feature_source: string, name of the feature source + feature_id: string, identifier of the feature + simplified: bool, simplified, default is True + split_catchment: bool, split catchment, default is False + as_json: bool, return basin as JSON is set to True, otherwise return + as GeoDataFrame, default is False + + Returns + ------- + gdf: GeoDataFrame or dict + GeoDataFrame/dict of basin + + Examples + -------- + .. doctest:: + + >>> # Get basin for a feature source: WQP and feature id: USGS-01031500 + >>> gdf = dataretrieval.nldi.get_basin( + ... feature_source="WQP", feature_id="USGS-01031500" + ... ) + """ + # validate the feature source + _validate_data_source(feature_source) + if not feature_id: + raise ValueError('feature_id is required') + + url = f'{NLDI_API_BASE_URL}/{feature_source}/{feature_id}/basin' + simplified = str(simplified).lower() + split_catchment = str(split_catchment).lower() + query_params = {'simplified': simplified, 'splitCatchment': split_catchment} + err_msg = ( + f"Error getting basin for feature source '{feature_source}' and " + f"feature_id '{feature_id}'" + ) + feature_collection = _query_nldi(url, query_params, err_msg) + if as_json: + return feature_collection + gdf = gpd.GeoDataFrame.from_features(feature_collection) + return gdf + + +def get_features( + data_source: Optional[str] = None, + navigation_mode: Optional[str] = None, + distance: int = 50, + feature_source: Optional[str] = None, + feature_id: Optional[str] = None, + comid: Optional[int] = None, + lat: Optional[float] = None, + long: Optional[float] = None, + stop_comid: Optional[int] = None, + as_json: bool = False, +) -> Union[gpd.GeoDataFrame, dict]: + """Gets all features found along the specified navigation either by + comid or feature source as points in WGS84 lat/long coordinates - a GeoDataFrame + containing a point geometry. + + Parameters + ---------- + feature_source: string, optional, name of the feature source, + required if comid is not provided + feature_id: string, optional, identifier of the feature, + required if comid is not provided + navigation_mode: string, navigation mode, allowed values are 'UM', 'DM', 'UT', 'DD' + data_source: string, data source + distance: int, distance in kilometers, default is 50 + comid: integer, optional, comid, required if feature source is not provided + lat: float, optional, latitude, if provided, long is also required + long: float, optional, longitude, if provided, lat is also required + stop_comid: integer, optional, stop comid + as_json: bool, optional, return features as JSON if set to True, + otherwise return as GeoDataFrame, default is False + + Returns + ------- + gdf: GeoDataFrame or dict + GeoDataFrame/dict of features + + Examples + -------- + .. doctest:: + + >>> # Get registered features for a feature source: WQP, + >>> # feature id: USGS-01031500 + >>> gdf = dataretrieval.nldi.get_features( + ... feature_source="WQP", feature_id="USGS-01031500" + ... ) + >>> # Get features for a feature source: WQP, feature id: USGS-01031500, + >>> # and data source: nwissite in the upstream main + >>> gdf = dataretrieval.nldi.get_features( + ... feature_source="WQP", + ... feature_id="USGS-01031500", + ... navigation_mode="UM", + ... data_source="nwissite", + ... distance=50, + ... ) + >>> # Get features for a comid: 13294314, and data source: nwissite + >>> # in the upstream main + >>> gdf = dataretrieval.nldi.get_features( + ... comid=13294314, + ... navigation_mode="UM", + ... data_source="nwissite", + ... distance=50, + ... ) + >>> # Get features for a latitude: 43.073051 and longitude: -89.401230 + >>> gdf = dataretrieval.nldi.get_features(lat=43.073051, long=-89.401230) + """ + + # check only one origin is provided + if (lat and long is None) or (long and lat is None): + raise ValueError('Both lat and long are required') + + if lat: + if comid: + raise ValueError( + 'Provide only one origin type - comid cannot be provided' + ' with lat or long' + ) + if feature_source or feature_id: + raise ValueError( + 'Provide only one origin type - feature_source and feature_id cannot' + ' be provided with lat or long' + ) + + if not lat: + if comid or data_source: + if navigation_mode is None: + raise ValueError( + 'navigation_mode is required if comid or data_source is provided' + ) + # validate the feature source and comid + _validate_feature_source_comid(feature_source, feature_id, comid) + # validate the data source + if data_source: + _validate_data_source(data_source) + # validate feature source + _validate_data_source(feature_source) + # validate the navigation mode + if navigation_mode: + _validate_navigation_mode(navigation_mode) + + if lat: + url = f'{NLDI_API_BASE_URL}/comid/position' + query_params = {'coords': f'POINT({long} {lat})'} + else: + if navigation_mode: + if feature_source: + url = f'{NLDI_API_BASE_URL}/{feature_source}/{feature_id}/navigation' + else: + url = f'{NLDI_API_BASE_URL}/comid/{comid}/navigation' + url += f'/{navigation_mode}/{data_source}' + query_params = {'distance': str(distance)} + if stop_comid is not None: + query_params['stopComid'] = str(stop_comid) + else: + url = f'{NLDI_API_BASE_URL}/{feature_source}/{feature_id}' + query_params = {} + + if lat: + err_msg = f"Error getting features for lat '{lat}'" f" and long '{long}'" + elif feature_source: + err_msg = ( + f"Error getting features for feature source '{feature_source}'" + f" and feature_id '{feature_id}, and data source '{data_source}'" + ) + else: + err_msg = ( + f"Error getting features for comid '{comid}'" + f" and data source '{data_source}'" + ) + + feature_collection = _query_nldi(url, query_params, err_msg) + if as_json: + return feature_collection + gdf = gpd.GeoDataFrame.from_features(feature_collection) + return gdf + + +# TODO: This function can cause timeout error for some data sources +# - may be we shouldn't provide this function? +def get_features_by_data_source(data_source: str) -> gpd.GeoDataFrame: + """Gets all features found for the specified data source as + points in WGS84 lat/long coordinates as GeoDataFrame containing a point geometry. + + Parameters + ---------- + data_source: string, data source + + Returns + ------- + gdf: GeoDataFrame + GeoDataFrame of features + + Examples + -------- + .. doctest:: + + >>> # Get features for a feature wqp and feature_id USGS-01031500 + >>> gdf = dataretrieval.nldi.get_features_by_data_source(data_source="nwissite") + """ + # validate the data source + _validate_data_source(data_source) + url = f'{NLDI_API_BASE_URL}/{data_source}' + err_msg = f"Error getting features for data source '{data_source}'" + feature_collection = _query_nldi(url, {}, err_msg) + gdf = gpd.GeoDataFrame.from_features(feature_collection) + return gdf + + +def search( + feature_source: Optional[str] = None, + feature_id: Optional[str] = None, + navigation_mode: Optional[str] = None, + data_source: Optional[str] = None, + find: Literal['basin', 'flowlines', 'features'] = 'features', + comid: Optional[int] = None, + lat: Optional[float] = None, + long: Optional[float] = None, + distance: int = 50, +) -> dict: + """Searches for the specified feature in NLDI and returns the results + as a dictionary. + + Parameters + ---------- + feature_source: string, name of the feature source + feature_id: string, identifier of the feature + navigation_mode: string, optional, navigation mode, + allowed values are 'UM', 'DM', 'UT', 'DD' + data_source: string, optional, data source + find: string, search for 'basin', 'flowlines', or 'features', default is 'features' + comid: int, optional, comid, default is None + lat: float, optional, latitude, default is None + long: float, optional, longitude, default is None + distance: int, optional, distance in kilometers, default is 50 + + Returns + ------- + dict: search results + + Examples + -------- + .. doctest:: + + >>> # Search for aggregated basin for feature source: WQP + >>> # and feature id: USGS-01031500 + >>> search_results = dataretrieval.nldi.search( + ... feature_source="WQP", feature_id="USGS-01031500", find='basin' + ... ) + >>> # Search for flowlines for feature source: WQP and + >>> # feature id: USGS-01031500 in the upstream main + >>> search_results = dataretrieval.nldi.search( + ... feature_source="WQP", + ... feature_id="USGS-01031500", + ... navigation_mode="UM", + ... find='flowlines', + ... ) + >>> # Get registered features for a feature source: WQP, + >>> # feature id: USGS-01031500 + >>> gdf = dataretrieval.nldi.get_features( + ... feature_source="WQP", feature_id="USGS-01031500" + ... ) + >>> # Search for features for feature source: WQP, feature id: USGS-01031500, + >>> # and data source: census2020-nhdpv2 in the upstream main + >>> search_results = dataretrieval.nldi.search( + ... feature_source="WQP", + ... feature_id="USGS-01031500", + ... data_source='census2020-nhdpv2', + ... navigation_mode='UM', + ... find='features', + ... ) + >>> # Search for features for comid: 13294314, + >>> # and data source: census2020-nhdpv2 in the upstream main + >>> search_results = dataretrieval.nldi.search( + ... comid=13294314, data_source="census2020-nhdpv2", navigation_mode="UM" + ... ) + >>> # Search for flowlines for comid: 13294314 in the upstream main + >>> search_results = dataretrieval.nldi.search( + ... comid=13294314, navigation_mode="UM", find="flowlines" + ... ) + >>> # Search for features for latitude: 43.073051 and longitude: -89.401230 + >>> search_results = dataretrieval.nldi.search(lat=43.073051, long=-89.401230) + + """ + if (lat and long is None) or (long and lat is None): + raise ValueError('Both lat and long are required') + + # validate find + find = find.lower() + if find not in ('basin', 'flowlines', 'features'): + raise ValueError( + f'Invalid value for find: {find} - allowed values are:' + f" 'basin', 'flowlines', or 'features'" + ) + if lat and find != 'features': + raise ValueError( + f'Invalid value for find: {find} - lat/long is to get features not {find}' + ) + if comid and find == 'basin': + raise ValueError( + 'Invalid value for find: basin - comid is to get features' + ' or flowlines not basin' + ) + + if lat: + # get features by hydrologic location + return get_features(lat=lat, long=long, as_json=True) + + if find == 'basin': + return get_basin( + feature_source=feature_source, feature_id=feature_id, as_json=True + ) + + if find == 'flowlines': + return get_flowlines( + navigation_mode=navigation_mode, + distance=distance, + feature_source=feature_source, + feature_id=feature_id, + comid=comid, + as_json=True, + ) + # here find == 'features' + return get_features( + data_source=data_source, + navigation_mode=navigation_mode, + distance=distance, + feature_source=feature_source, + feature_id=feature_id, + comid=comid, + as_json=True, + ) + + +def _validate_data_source(data_source: str): + # A helper function to validate user specified data source/feature source + + global _AVAILABLE_DATA_SOURCES + + # get the available data/feature sources - if not already cached + if _AVAILABLE_DATA_SOURCES is None: + url = f'{NLDI_API_BASE_URL}/' + available_data_sources = _query_nldi( + url, {}, 'Error getting available data sources' + ) + _AVAILABLE_DATA_SOURCES = [ds['source'] for ds in available_data_sources] + if data_source not in _AVAILABLE_DATA_SOURCES: + err_msg = ( + f"Invalid data source '{data_source}'." + f' Available data sources are: {_AVAILABLE_DATA_SOURCES}' + ) + raise ValueError(err_msg) + + +def _validate_navigation_mode(navigation_mode: str): + navigation_mode = navigation_mode.upper() + if navigation_mode not in ('UM', 'DM', 'UT', 'DD'): + raise TypeError(f"Invalid navigation mode '{navigation_mode}'") + + +def _validate_feature_source_comid( + feature_source: Optional[str], feature_id: Optional[str], comid: Optional[int] +): + if feature_source is not None and feature_id is None: + raise ValueError('feature_id is required if feature_source is provided') + if feature_id is not None and feature_source is None: + raise ValueError('feature_source is required if feature_id is provided') + if comid is not None and feature_source is not None: + raise ValueError( + 'Specify only one origin type - comid and feature_source' + ' cannot be provided together' + ) + if comid is None and feature_source is None: + raise ValueError( + 'Specify one origin type - comid or feature_source is required' + ) diff --git a/pyproject.toml b/pyproject.toml index 426f873..a281b41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,14 +11,13 @@ keywords = ["USGS", "water data"] license = {file = "LICENSE.md"} maintainers = [ {name = "Timothy Hodson", email = "thodson@usgs.gov"}, - {name = "Jayaram Hariharan", email = "jhariharan@usgs.gov"}, ] classifiers = [ "Programming Language :: Python :: 3", ] dependencies = [ "requests", - "pandas", + "pandas==2.*", ] dynamic = ["version"] @@ -28,10 +27,19 @@ packages = ["dataretrieval", "dataretrieval.codes"] [project.optional-dependencies] test = [ "pytest > 5.0.0", - "pytest-cov[all]" + "pytest-cov[all]", + "coverage", + "requests-mock", + "flake8", ] doc = [ "sphinx", + "sphinx_rtd_theme", + "nbsphinx", + "nbsphinx_link", +] +nldi = [ + 'geopandas>=0.10' ] [project.urls] diff --git a/requirements-dev.txt b/requirements-dev.txt index 0e66e5e..d6a6f51 100755 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,6 @@ numpy<2 pandas==2.* +geopandas==0.14.* scipy python-dateutil requests diff --git a/requirements.txt b/requirements.txt deleted file mode 100755 index e6a6fd2..0000000 --- a/requirements.txt +++ /dev/null @@ -1,4 +0,0 @@ -numpy<2 -pandas==2.* -python-dateutil -requests diff --git a/tests/data/nldi_get_basin.json b/tests/data/nldi_get_basin.json new file mode 100644 index 0000000..5210e43 --- /dev/null +++ b/tests/data/nldi_get_basin.json @@ -0,0 +1,138 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [-89.467166934, 43.120532162], + [-89.461615766, 43.12632345], + [-89.457260835, 43.127037725], + [-89.452061009, 43.124187365], + [-89.4476819, 43.119429024], + [-89.439928469, 43.119445644], + [-89.428664489, 43.113435904], + [-89.410715151, 43.106836358], + [-89.413577818, 43.100214712], + [-89.414991109, 43.089543698], + [-89.422806579, 43.085870913], + [-89.430063704, 43.088309393], + [-89.441315037, 43.083364081], + [-89.444278818, 43.084620004], + [-89.450179911, 43.081715309], + [-89.451427898, 43.079513559], + [-89.464561163, 43.078447595], + [-89.466686537, 43.076682871], + [-89.4622099, 43.07306458], + [-89.465497169, 43.073234059], + [-89.468704754, 43.07134039], + [-89.469622381, 43.068424824], + [-89.467935617, 43.067497217], + [-89.470726914, 43.06540292], + [-89.470430177, 43.062692826], + [-89.466400073, 43.056302895], + [-89.469802035, 43.053666055], + [-89.47601985, 43.057901927], + [-89.476585982, 43.060280486], + [-89.478603327, 43.060411566], + [-89.483458574, 43.058438858], + [-89.484967442, 43.056130059], + [-89.491406587, 43.054388451], + [-89.494069541, 43.055509411], + [-89.493868228, 43.06153445], + [-89.500475724, 43.063815698], + [-89.506329775, 43.06379093], + [-89.507540669, 43.061129535], + [-89.516487667, 43.05889596], + [-89.524196291, 43.0484005], + [-89.527027161, 43.049865572], + [-89.531212693, 43.048578393], + [-89.53168683, 43.05078274], + [-89.537781776, 43.052965206], + [-89.537977928, 43.05550807], + [-89.544353411, 43.058384424], + [-89.545783506, 43.061283656], + [-89.551286859, 43.061283754], + [-89.554899419, 43.062989677], + [-89.555177648, 43.065189554], + [-89.55939716, 43.069584622], + [-89.552552004, 43.070032995], + [-89.551027329, 43.072160878], + [-89.55664221, 43.078164337], + [-89.561552454, 43.080518638], + [-89.557979773, 43.081411202], + [-89.553540642, 43.086194967], + [-89.548701193, 43.086177316], + [-89.546825331, 43.088023965], + [-89.543205962, 43.087800221], + [-89.540831467, 43.089363501], + [-89.536587878, 43.095690791], + [-89.536402562, 43.103900066], + [-89.539222509, 43.106589488], + [-89.543754931, 43.106648012], + [-89.545473151, 43.108651969], + [-89.551215165, 43.105435169], + [-89.562937764, 43.104929008], + [-89.571631233, 43.102745105], + [-89.577430373, 43.106944886], + [-89.575279549, 43.112421282], + [-89.585534254, 43.110302501], + [-89.590268184, 43.11100234], + [-89.591233389, 43.112975078], + [-89.590180668, 43.11496155], + [-89.593396468, 43.118692324], + [-89.590911252, 43.118300423], + [-89.585126608, 43.12232665], + [-89.588527844, 43.125843725], + [-89.594046461, 43.126263171], + [-89.584750406, 43.134728013], + [-89.58703379, 43.136667616], + [-89.58646025, 43.139891225], + [-89.58311069, 43.140790363], + [-89.58050643, 43.147945499], + [-89.577277976, 43.149190149], + [-89.577524762, 43.155001208], + [-89.575687513, 43.156361384], + [-89.574702434, 43.160718603], + [-89.575498624, 43.163477344], + [-89.572475709, 43.166520978], + [-89.573423699, 43.16805986], + [-89.571498421, 43.168773113], + [-89.561668082, 43.160869482], + [-89.556299248, 43.163934156], + [-89.5530407, 43.163969446], + [-89.553533801, 43.154687139], + [-89.542983929, 43.149942779], + [-89.543949065, 43.14881666], + [-89.541736611, 43.147335113], + [-89.544166951, 43.145507198], + [-89.540220508, 43.141656916], + [-89.536084993, 43.147942882], + [-89.529435603, 43.145701478], + [-89.526609809, 43.142382532], + [-89.530611508, 43.138913019], + [-89.526215839, 43.137656712], + [-89.525317304, 43.134190086], + [-89.521417176, 43.136858837], + [-89.515079469, 43.136375804], + [-89.512331543, 43.131812042], + [-89.509033557, 43.130035294], + [-89.499032624, 43.13174139], + [-89.495385036, 43.1363024], + [-89.476329648, 43.136222116], + [-89.475062917, 43.133358252], + [-89.479607077, 43.13215007], + [-89.482220611, 43.126289637], + [-89.475491468, 43.126823191], + [-89.471635553, 43.125462527], + [-89.471517511, 43.122731655], + [-89.467166934, 43.120532162] + ] + ] + }, + "properties": {} + } + ] +} diff --git a/tests/data/nldi_get_features_by_comid.json b/tests/data/nldi_get_features_by_comid.json new file mode 100644 index 0000000..bd86d21 --- /dev/null +++ b/tests/data/nldi_get_features_by_comid.json @@ -0,0 +1,770 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5098433, 43.0872176] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-054279485", + "name": "STRICKER'S POND AT MIDDLETON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-054279485/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-054279485/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5, 43.08] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10001231", + "name": "UN LAKE - UN LAKE", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10001231/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10001231/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.47222, 43.067223] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10034975", + "name": "South Kenosha Drive Storm Sewer in Madison (USGS 430402089282000)", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10034975/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10034975/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.481995, 43.09372] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10037966", + "name": "Lake Mendota - Marshall Park Beach", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10037966/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10037966/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4726, 43.0877] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10043400", + "name": "Lake Mendota at Upham Ct", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10043400/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10043400/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.509456, 43.087011] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133461", + "name": "Stricker Pond - Deep Hole", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133461/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133461/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.50232, 43.0901] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133524", + "name": "Tiedeman Pond - E Side Gammon Rd", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133524/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133524/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.483055, 43.104164] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133464", + "name": "Lake Mendota -- Middleton Boat Ramp", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133464/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133464/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.48351, 43.094044] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10017941", + "name": "Lake Mendota -- Marshall Park Boat Park", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10017941/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10017941/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.45224, 43.095856] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10031991", + "name": "Lake Mendota - Pheasant Branch Deep Area", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10031991/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10031991/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.46969, 43.108173] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10033468", + "name": "Lake Mendota - Lake Mendota Beach", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10033468/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10033468/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4708333, 43.0791667] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-05427965", + "name": "SPRING HARBOR STORM SEWER AT MADISON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-05427965/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-05427965/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.470116, 43.108547] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10017575", + "name": "Lake Mendota -- Mendota County Park Boat Launch", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10017575/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10017575/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.463173, 43.109038] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10043399", + "name": "Lake Mendota - east end St. Cyr Rd", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10043399/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10043399/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.512275, 43.087842] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133532", + "name": "Stonefield Infilitration Pond At Middleton WI", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133532/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133532/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.487343, 43.0730514] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430423089291401", + "name": "OWEN PARK RAIN GARDEN AT MADISON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430423089291401/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430423089291401/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.42417, 43.087334] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10039736", + "name": "Lake Mendota - Picnic Point Beach", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10039736/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10039736/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4722222, 43.0672222] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430402089282000", + "name": "SOUTH KENOSHA DRIVE STORM SEWER AT MADISON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430402089282000/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430402089282000/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5048432, 43.0902731] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-05427949", + "name": "TIEDEMAN'S POND AT MIDDLETON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-05427949/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-05427949/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.49325, 43.0654444] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430356089293601", + "name": "SOUTH YELLOWSTONE DRIVE STORM SEWER AT MADISON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430356089293601/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430356089293601/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.442342, 43.0874956] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430519089263001", + "name": "DN-07/09E/16-0303", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430519089263001/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430519089263001/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.47183, 43.06603] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10040786", + "name": "South Kenosha Drive (East) Storm Sewer at Madison WI", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10040786/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10040786/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5017877, 43.0874954] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430515089300601", + "name": "STONEFIELD INFILTRATION POND AT MIDDLETON", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430515089300601/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430515089300601/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.466787, 43.0813846] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430453089280001", + "name": "DN-07/09E/18-0003SP", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430453089280001/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430453089280001/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.46917, 43.08278] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133542", + "name": "LAKE MENDOTA - SPRING HARBOR BEACH", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133542/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133542/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.482442, 43.093969] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133536", + "name": "Lake Mendota - West Side", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133536/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133536/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4555556, 43.0998611] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430600089272001", + "name": "LAKE MENDOTA, WEST BAY, AT MADISON, WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430600089272001/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430600089272001/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.505323, 43.090517] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133460", + "name": "Tiedman Pond - Deep Hole", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133460/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133460/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.469463, 43.113437] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133515", + "name": "SALERNO CT. MIDDLETON - ARBOR LAKES", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133515/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133515/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5053988, 43.0899953] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430524089301901", + "name": "TIEDMAN POND AT MIDDLETON", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430524089301901/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430524089301901/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4940097, 43.0933286] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430540089294001", + "name": "DN-07/08E/12-0921", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430540089294001/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430540089294001/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.49325, 43.065445] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10040785", + "name": "South Yellowstone Drive Storm Sewer at Madison WI", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10040785/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10040785/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.457695, 43.081473] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133221", + "name": "Lake Mendota - Madison Water Dist", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133221/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133221/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.469826, 43.08108] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10017443", + "name": "Lake Mendota -- Spring Harbor", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10017443/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10017443/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.47362, 43.069195] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10033592", + "name": "Storm Sewer at Kenosha Dr in Madison [KENARM-1]", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10033592/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10033592/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.505, 43.091] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "NALMS-F1842718", + "name": "Tiedemans Pond, Dane County, WI, USA", + "uri": "https://www.waterqualitydata.us/provider/STORET/NALMS/NALMS-F1842718/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/NALMS-F1842718/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.483176, 43.104995] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430615089285701", + "name": "DN-07/08E/01-0214", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430615089285701/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430615089285701/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.510414, 43.0878] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10022809", + "name": "Stricker Pond Nw Corner", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10022809/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10022809/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.47083, 43.079166] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10032770", + "name": "University Ave storm sewer at Spring Harbor", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10032770/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10032770/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4801722, 43.0742833] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430427089284901", + "name": "DN-07/09E/19-0064", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430427089284901/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430427089284901/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5, 43.08] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-10001232", + "name": "Strickers Pond", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-10001232/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-10001232/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.41667, 43.09999] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "WIDNR_WQX-133318", + "name": "Lake Mendota - Central Deep Hole", + "uri": "https://www.waterqualitydata.us/provider/STORET/WIDNR_WQX/WIDNR_WQX-133318/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/WIDNR_WQX-133318/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4718333, 43.0660278] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430358089281901", + "name": "SOUTH KENOSHA DRIVE (EAST) STORM SEWR @ MADISON,WI", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430358089281901/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430358089281901/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.4695649, 43.0777735] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "USGS-430440089281001", + "name": "DN-07/09E/18-0715", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-430440089281001/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/USGS-430440089281001/navigation" + } + }, + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.42, 43.105] + }, + "properties": { + "type": "varies", + "source": "WQP", + "sourceName": "Water Quality Portal", + "identifier": "NALMS-F1569337", + "name": "Lake Mendota, Dane County, WI, USA", + "uri": "https://www.waterqualitydata.us/provider/STORET/NALMS/NALMS-F1569337/", + "comid": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/wqp/NALMS-F1569337/navigation" + } + } + ] +} diff --git a/tests/data/nldi_get_features_by_feature_source_with_nav_mode.json b/tests/data/nldi_get_features_by_feature_source_with_nav_mode.json new file mode 100644 index 0000000..593425a --- /dev/null +++ b/tests/data/nldi_get_features_by_feature_source_with_nav_mode.json @@ -0,0 +1,185 @@ +{ + "features": [ + { + "geometry": { + "coordinates": [-89.5361111, 43.1111111], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-05427943", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-05427943/navigation", + "measure": 0, + "reachcode": "07090002007651", + "name": "PHEASANT BRANCH AT AIRPORT ROAD NEAR MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13293676", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/05427943", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.4555556, 43.0998611], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-430600089272001", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-430600089272001/navigation", + "measure": 59.3341, + "reachcode": "07090002008384", + "name": "LAKE MENDOTA, WEST BAY, AT MADISON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294314", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/430600089272001", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.52151, 43.09860617], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-054279465", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-054279465/navigation", + "measure": 53.7958, + "reachcode": "07090002007650", + "name": "S FORK PHEASANT BRANCH @ DEMING WAY @ MIDDLETON,WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294264", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/054279465", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.493454, 43.10443947], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-05427950", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-05427950/navigation", + "measure": 2.32298, + "reachcode": "07090002007650", + "name": "PHEASANT BRANCH AT CENTURY AVE AT MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294264", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/05427950", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.5287322, 43.1044393], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-054279435", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-054279435/navigation", + "measure": 72.0559, + "reachcode": "07090002007650", + "name": "PHEASANT BR W. OF CONFLUENCE POND @ MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294264", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/054279435", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.5116667, 43.1033333], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-05427948", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-05427948/navigation", + "measure": 40.6051151144, + "reachcode": "07090002007650", + "name": "PHEASANT BRANCH AT MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294264", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/05427948", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.5167877, 43.1030505], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-054279475", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-054279475/navigation", + "measure": 48.974, + "reachcode": "07090002007650", + "name": "PHEASANT BRANCH UPSTREAM OF HWY 12 @ MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294264", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/054279475", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.5138889, 43.10777778], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-430628089305001", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-430628089305001/navigation", + "measure": 43.532, + "reachcode": "07090002007650", + "name": "GW QUALITY ASSURANCE-NAWQA WAREHOUSE-MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13294264", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/430628089305001", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + }, + { + "geometry": { + "coordinates": [-89.4837316, 43.10607834], + "type": "Point" + }, + "type": "Feature", + "properties": { + "identifier": "USGS-05427952", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/nwissite/USGS-05427952/navigation", + "measure": 46.391, + "reachcode": "07090002007647", + "name": "PHEASANT BRANCH AT MOUTH AT MIDDLETON, WI", + "source": "nwissite", + "sourceName": "NWIS Surface Water Sites", + "comid": "13293696", + "type": "hydrolocation", + "uri": "https://waterdata.usgs.gov/monitoring-location/05427952", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + } + ], + "type": "FeatureCollection" +} diff --git a/tests/data/nldi_get_features_by_feature_source_without_nav_mode.json b/tests/data/nldi_get_features_by_feature_source_without_nav_mode.json new file mode 100644 index 0000000..f640e38 --- /dev/null +++ b/tests/data/nldi_get_features_by_feature_source_without_nav_mode.json @@ -0,0 +1,23 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [-89.5098433, 43.0872176] + }, + "properties": { + "identifier": "USGS-054279485", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/WQP/USGS-054279485/navigation", + "name": "STRICKER'S POND AT MIDDLETON, WI", + "source": "WQP", + "sourceName": "Water Quality Portal", + "comid": "13294314", + "type": "varies", + "uri": "https://www.waterqualitydata.us/provider/NWIS/USGS-WI/USGS-054279485/", + "mainstem": "https://geoconnex.us/ref/mainstems/575519" + } + } + ] +} diff --git a/tests/data/nldi_get_features_by_lat_long.json b/tests/data/nldi_get_features_by_lat_long.json new file mode 100644 index 0000000..3bdc475 --- /dev/null +++ b/tests/data/nldi_get_features_by_lat_long.json @@ -0,0 +1,47 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.482287705, 43.1049596], + [-89.482173502, 43.104764298], + [-89.481962003, 43.104193598], + [-89.478003301, 43.1009003], + [-89.474274702, 43.0990991], + [-89.471394107, 43.098147698], + [-89.470654801, 43.098110899], + [-89.469584204, 43.097653598], + [-89.455723904, 43.096961297], + [-89.4536274, 43.097529493], + [-89.451938607, 43.097714297], + [-89.450211607, 43.098300897], + [-89.449472405, 43.098263897], + [-89.448879704, 43.098638095], + [-89.448325306, 43.098610297], + [-89.4471654, 43.099090695], + [-89.446375206, 43.099589594], + [-89.445820704, 43.0995619], + [-89.441537805, 43.101635799], + [-89.435227506, 43.105492599], + [-89.433882602, 43.105963595], + [-89.433328107, 43.105935797], + [-89.432537705, 43.106434599], + [-89.430083804, 43.106849998], + [-89.429293305, 43.1073488], + [-89.426310502, 43.107468195], + [-89.410033204, 43.106784396] + ] + }, + "properties": { + "identifier": "13294314", + "navigation": "https://labs.waterdata.usgs.gov/api/nldi/linked-data/comid/13294314/navigation", + "source": "comid", + "sourceName": "NHDPlus comid", + "comid": "13294314" + } + } + ] +} diff --git a/tests/data/nldi_get_flowlines.json b/tests/data/nldi_get_flowlines.json new file mode 100644 index 0000000..5ffa035 --- /dev/null +++ b/tests/data/nldi_get_flowlines.json @@ -0,0 +1,43 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.482287705, 43.1049596], + [-89.482173502, 43.104764298], + [-89.481962003, 43.104193598], + [-89.478003301, 43.1009003], + [-89.474274702, 43.0990991], + [-89.471394107, 43.098147698], + [-89.470654801, 43.098110899], + [-89.469584204, 43.097653598], + [-89.455723904, 43.096961297], + [-89.4536274, 43.097529493], + [-89.451938607, 43.097714297], + [-89.450211607, 43.098300897], + [-89.449472405, 43.098263897], + [-89.448879704, 43.098638095], + [-89.448325306, 43.098610297], + [-89.4471654, 43.099090695], + [-89.446375206, 43.099589594], + [-89.445820704, 43.0995619], + [-89.441537805, 43.101635799], + [-89.435227506, 43.105492599], + [-89.433882602, 43.105963595], + [-89.433328107, 43.105935797], + [-89.432537705, 43.106434599], + [-89.430083804, 43.106849998], + [-89.429293305, 43.1073488], + [-89.426310502, 43.107468195], + [-89.410033204, 43.106784396] + ] + }, + "properties": { + "nhdplus_comid": "13294314" + } + } + ] +} diff --git a/tests/data/nldi_get_flowlines_by_comid.json b/tests/data/nldi_get_flowlines_by_comid.json new file mode 100644 index 0000000..5b9c2d9 --- /dev/null +++ b/tests/data/nldi_get_flowlines_by_comid.json @@ -0,0 +1,285 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.482287705, 43.1049596], + [-89.482173502, 43.104764298], + [-89.481962003, 43.104193598], + [-89.478003301, 43.1009003], + [-89.474274702, 43.0990991], + [-89.471394107, 43.098147698], + [-89.470654801, 43.098110899], + [-89.469584204, 43.097653598], + [-89.455723904, 43.096961297], + [-89.4536274, 43.097529493], + [-89.451938607, 43.097714297], + [-89.450211607, 43.098300897], + [-89.449472405, 43.098263897], + [-89.448879704, 43.098638095], + [-89.448325306, 43.098610297], + [-89.4471654, 43.099090695], + [-89.446375206, 43.099589594], + [-89.445820704, 43.0995619], + [-89.441537805, 43.101635799], + [-89.435227506, 43.105492599], + [-89.433882602, 43.105963595], + [-89.433328107, 43.105935797], + [-89.432537705, 43.106434599], + [-89.430083804, 43.106849998], + [-89.429293305, 43.1073488], + [-89.426310502, 43.107468195], + [-89.410033204, 43.106784396] + ] + }, + "properties": { + "nhdplus_comid": "13294314" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.483727604, 43.107564196], + [-89.483571202, 43.10729], + [-89.483445406, 43.106809996], + [-89.483569205, 43.106261298], + [-89.483599804, 43.105941199], + [-89.483443506, 43.105781294], + [-89.482850306, 43.105553299], + [-89.482381806, 43.105256498], + [-89.482287705, 43.1049596] + ] + }, + "properties": { + "nhdplus_comid": "13293696" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.492553301, 43.105474696], + [-89.491741903, 43.105338395], + [-89.4901511, 43.105522998], + [-89.489932805, 43.105637498], + [-89.489902005, 43.105820395], + [-89.489777602, 43.106003493], + [-89.489278801, 43.106278397], + [-89.488779604, 43.106255993], + [-89.488092504, 43.105913796], + [-89.487811901, 43.106005497], + [-89.487531707, 43.106348693], + [-89.486752704, 43.1068068], + [-89.4859742, 43.107584797], + [-89.485537805, 43.107836694], + [-89.484789006, 43.107814595], + [-89.483727604, 43.107564196] + ] + }, + "properties": { + "nhdplus_comid": "13293694" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.536097303, 43.113352194], + [-89.536100604, 43.110974595], + [-89.535757802, 43.110677198], + [-89.531701401, 43.110742696], + [-89.531295903, 43.110673897], + [-89.531398706, 43.104364499], + [-89.531024806, 43.104044199], + [-89.530650601, 43.103906699], + [-89.521821305, 43.103990898], + [-89.521509305, 43.103944898], + [-89.521322206, 43.103921898], + [-89.520792201, 43.103669994], + [-89.520481005, 43.1032812], + [-89.520418905, 43.103075296], + [-89.520045206, 43.102709293], + [-89.519858107, 43.102594793], + [-89.519140601, 43.102571294], + [-89.518204302, 43.102753296], + [-89.516800202, 43.102889195], + [-89.516331807, 43.103163198], + [-89.515489005, 43.103436694], + [-89.514521703, 43.103550099], + [-89.513523303, 43.103549197], + [-89.512057304, 43.103342094], + [-89.510653302, 43.103386499], + [-89.509904705, 43.103317194], + [-89.508875601, 43.103064694], + [-89.508532606, 43.102995798], + [-89.508345202, 43.103087097], + [-89.508189, 43.103224099], + [-89.508157402, 43.103475496], + [-89.508000806, 43.1037497], + [-89.507907301, 43.103772394], + [-89.507782005, 43.104000896], + [-89.507655703, 43.104800895], + [-89.507343404, 43.104983598], + [-89.506875202, 43.105074495], + [-89.506532304, 43.104936995], + [-89.506033801, 43.104547895], + [-89.505784705, 43.104250498], + [-89.504974701, 43.103655294], + [-89.503540605, 43.103082195], + [-89.502760604, 43.103104293], + [-89.5023553, 43.103058197], + [-89.501981303, 43.102874897], + [-89.501763701, 43.102417499], + [-89.501639701, 43.102028698], + [-89.501390606, 43.101754196], + [-89.500735603, 43.1017306], + [-89.500127606, 43.101945899], + [-89.499566704, 43.102312297], + [-89.499255307, 43.102609798], + [-89.498506702, 43.102656499], + [-89.498226106, 43.102725297], + [-89.497727901, 43.1032288], + [-89.497291304, 43.103320695], + [-89.496511303, 43.1033215], + [-89.4954504, 43.103208296], + [-89.494296104, 43.103255399], + [-89.494077802, 43.103324294], + [-89.493922204, 43.1034844], + [-89.493580006, 43.103987694], + [-89.493051507, 43.104948394], + [-89.492553301, 43.105474696] + ] + }, + "properties": { + "nhdplus_comid": "13294264" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.551213205, 43.129066996], + [-89.551182806, 43.128358297], + [-89.551089302, 43.1282897], + [-89.551089406, 43.128198296], + [-89.550808601, 43.1280609], + [-89.548717603, 43.128082499], + [-89.546127006, 43.128103696], + [-89.545721702, 43.127806298], + [-89.545379005, 43.127257399], + [-89.543570004, 43.126227498], + [-89.542166501, 43.125609294], + [-89.541854702, 43.125334896], + [-89.541886106, 43.125220597], + [-89.541792504, 43.125174798], + [-89.541730307, 43.124991894], + [-89.541450106, 43.124511696], + [-89.540608101, 43.123985298], + [-89.540483601, 43.123665199], + [-89.540422305, 43.122819297], + [-89.540517002, 43.122019194], + [-89.540423803, 43.121630497], + [-89.540330306, 43.121539094], + [-89.540237002, 43.121287495], + [-89.540112406, 43.121127397], + [-89.5400813, 43.121058799], + [-89.539863303, 43.120670095], + [-89.539614402, 43.120098293], + [-89.539427802, 43.119732395], + [-89.539022505, 43.119343594], + [-89.5389916, 43.119137898], + [-89.538898103, 43.119069196], + [-89.5387742, 43.118406199], + [-89.538711905, 43.118291795], + [-89.538556807, 43.117582999], + [-89.538651906, 43.116462998], + [-89.538622007, 43.115388498], + [-89.538341902, 43.114885397], + [-89.538030006, 43.114793696], + [-89.536282606, 43.114746697], + [-89.536158003, 43.114586599], + [-89.536097303, 43.113352194] + ] + }, + "properties": { + "nhdplus_comid": "13293676" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.551271103, 43.133250393], + [-89.551213205, 43.129066996] + ] + }, + "properties": { + "nhdplus_comid": "13293620" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.554787301, 43.143699296], + [-89.5545066, 43.143356293], + [-89.5540388, 43.142944597], + [-89.553539403, 43.142784297], + [-89.551572703, 43.142760299], + [-89.551292107, 43.142531596], + [-89.551271103, 43.133250393] + ] + }, + "properties": { + "nhdplus_comid": "13293612" + } + }, + { + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-89.556082003, 43.1598849], + [-89.555957302, 43.159656294], + [-89.555864103, 43.1592905], + [-89.555770606, 43.159038998], + [-89.555677205, 43.158764496], + [-89.555584207, 43.158147298], + [-89.555490702, 43.1579872], + [-89.555522904, 43.157027096], + [-89.555429406, 43.156821296], + [-89.555650204, 43.154626995], + [-89.555743903, 43.154512696], + [-89.555619501, 43.154146798], + [-89.5553701, 43.153758094], + [-89.555214405, 43.153277993], + [-89.555120803, 43.153209299], + [-89.554933906, 43.152820595], + [-89.554747805, 43.151563197], + [-89.554717705, 43.150534496], + [-89.554843202, 43.149871595], + [-89.554876104, 43.1482943], + [-89.554970503, 43.147631399], + [-89.554972202, 43.145939797], + [-89.554879002, 43.145505399], + [-89.554723203, 43.1452538], + [-89.554724701, 43.143859394], + [-89.554787301, 43.143699296] + ] + }, + "properties": { + "nhdplus_comid": "13293584" + } + } + ] +} diff --git a/tests/nldi_test.py b/tests/nldi_test.py new file mode 100644 index 0000000..d0fb4a2 --- /dev/null +++ b/tests/nldi_test.py @@ -0,0 +1,278 @@ +from geopandas import GeoDataFrame + +from dataretrieval.nldi import ( + NLDI_API_BASE_URL, + get_basin, + get_features, + get_flowlines, + search, +) + + +def mock_request_data_sources(requests_mock): + request_url = f'{NLDI_API_BASE_URL}/' + available_data_sources = [ + {'source': 'ca_gages'}, + {'source': 'census2020-nhdpv2'}, + {'source': 'epa_nrsa'}, + {'source': 'geoconnex-demo'}, + {'source': 'gfv11_pois'}, + {'source': 'huc12pp'}, + {'source': 'huc12pp_102020'}, + {'source': 'nmwdi-st'}, + {'source': 'npdes'}, + {'source': 'nwisgw'}, + {'source': 'nwissite'}, + {'source': 'ref_gage'}, + {'source': 'vigil'}, + {'source': 'wade'}, + {'source': 'WQP'}, + {'source': 'comid'}, + ] + requests_mock.get( + request_url, json=available_data_sources, headers={'mock_header': 'value'} + ) + + +def mock_request(requests_mock, request_url, file_path): + with open(file_path) as text: + requests_mock.get( + request_url, text=text.read(), headers={'mock_header': 'value'} + ) + + +def test_get_basin(requests_mock): + """Tests NLDI get basin query""" + request_url = ( + f'{NLDI_API_BASE_URL}/WQP/USGS-054279485/basin' + f'?simplified=true&splitCatchment=false' + ) + response_file_path = 'data/nldi_get_basin.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_basin(feature_source='WQP', feature_id='USGS-054279485') + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 1 + + +def test_get_flowlines(requests_mock): + """Tests NLDI get flowlines query using feature source as the origin""" + request_url = ( + f'{NLDI_API_BASE_URL}/WQP/USGS-054279485/navigation/UM/flowlines' + f'?distance=5&trimStart=false' + ) + response_file_path = 'data/nldi_get_flowlines.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_flowlines( + feature_source='WQP', feature_id='USGS-054279485', navigation_mode='UM' + ) + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 2 + + +def test_get_flowlines_by_comid(requests_mock): + """Tests NLDI get flowlines query using comid as the origin""" + request_url = ( + f'{NLDI_API_BASE_URL}/comid/13294314/navigation/UM/flowlines?distance=50' + ) + response_file_path = 'data/nldi_get_flowlines_by_comid.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_flowlines(navigation_mode='UM', comid=13294314, distance=50) + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 16 + + +def test_features_by_feature_source_with_navigation(requests_mock): + """Tests NLDI get features query using feature source as the origin + with navigation mode + """ + request_url = ( + f'{NLDI_API_BASE_URL}/WQP/USGS-054279485/navigation/UM/nwissite?distance=50' + ) + response_file_path = 'data/nldi_get_features_by_feature_source_with_nav_mode.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_features( + feature_source='WQP', + feature_id='USGS-054279485', + data_source='nwissite', + navigation_mode='UM', + distance=50, + ) + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 108 + + +def test_features_by_feature_source_without_navigation(requests_mock): + """Tests NLDI get features query using feature source as the origin + without navigation mode + """ + request_url = f'{NLDI_API_BASE_URL}/WQP/USGS-054279485' + response_file_path = ( + 'data/nldi_get_features_by_feature_source_without_nav_mode.json' + ) + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_features(feature_source='WQP', feature_id='USGS-054279485') + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 10 + + +def test_get_features_by_comid(requests_mock): + """Tests NLDI get features query using comid as the origin""" + request_url = f'{NLDI_API_BASE_URL}/comid/13294314/navigation/UM/WQP?distance=5' + response_file_path = 'data/nldi_get_features_by_comid.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_features( + comid=13294314, data_source='WQP', navigation_mode='UM', distance=5 + ) + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 405 + + +def test_get_features_by_lat_long(requests_mock): + """Tests NLDI get features query using lat/long as the origin""" + request_url = ( + f'{NLDI_API_BASE_URL}/comid/position?coords=POINT%28-89.509%2043.087%29' + ) + response_file_path = 'data/nldi_get_features_by_lat_long.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + gdf = get_features(lat=43.087, long=-89.509) + assert isinstance(gdf, GeoDataFrame) + assert gdf.size == 6 + + +def test_search_for_basin(requests_mock): + """Tests NLDI search query for basin""" + request_url = f'{NLDI_API_BASE_URL}/WQP/USGS-054279485/basin' + response_file_path = 'data/nldi_get_basin.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search( + feature_source='WQP', feature_id='USGS-054279485', find='basin' + ) + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'Polygon' + assert len(search_results['features'][0]['geometry']['coordinates'][0]) == 122 + + +def test_search_for_flowlines(requests_mock): + """Tests NLDI search query for flowlines""" + request_url = f'{NLDI_API_BASE_URL}/WQP/USGS-054279485/navigation/UM/flowlines' + response_file_path = 'data/nldi_get_flowlines.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search( + feature_source='WQP', + feature_id='USGS-054279485', + navigation_mode='UM', + find='flowlines', + ) + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'LineString' + assert len(search_results['features'][0]['geometry']['coordinates']) == 27 + + +def test_search_for_flowlines_by_comid(requests_mock): + """Tests NLDI search query for flowlines by comid""" + request_url = f'{NLDI_API_BASE_URL}/comid/13294314/navigation/UM/flowlines' + response_file_path = 'data/nldi_get_flowlines_by_comid.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search(comid=13294314, navigation_mode='UM', find='flowlines') + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'LineString' + assert len(search_results['features'][0]['geometry']['coordinates']) == 27 + + +def test_search_for_features_by_feature_source_with_navigation(requests_mock): + """Tests NLDI search query for features by feature source""" + request_url = ( + f'{NLDI_API_BASE_URL}/WQP/USGS-054279485/navigation/UM/nwissite?distance=50' + ) + response_file_path = 'data/nldi_get_features_by_feature_source_with_nav_mode.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search( + feature_source='WQP', + feature_id='USGS-054279485', + data_source='nwissite', + navigation_mode='UM', + find='features', + ) + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'Point' + assert len(search_results['features']) == 9 + + +def test_search_for_features_by_feature_source_without_navigation(requests_mock): + """Tests NLDI search query for features by feature source""" + request_url = f'{NLDI_API_BASE_URL}/WQP/USGS-054279485' + response_file_path = ( + 'data/nldi_get_features_by_feature_source_without_nav_mode.json' + ) + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search( + feature_source='WQP', feature_id='USGS-054279485', find='features' + ) + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'Point' + assert len(search_results['features']) == 1 + + +def test_search_for_features_by_comid(requests_mock): + """Tests NLDI search query for features by comid""" + request_url = f'{NLDI_API_BASE_URL}/comid/13294314/navigation/UM/WQP?distance=5' + response_file_path = 'data/nldi_get_features_by_comid.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search( + comid=13294314, + data_source='WQP', + navigation_mode='UM', + find='features', + distance=5, + ) + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'Point' + assert len(search_results['features']) == 45 + + +def test_search_for_features_by_lat_long(requests_mock): + """Tests NLDI search query for features by lat/long""" + request_url = ( + f'{NLDI_API_BASE_URL}/comid/position?coords=POINT%28-89.509%2043.087%29' + ) + response_file_path = 'data/nldi_get_features_by_lat_long.json' + mock_request_data_sources(requests_mock) + mock_request(requests_mock, request_url, response_file_path) + + search_results = search(lat=43.087, long=-89.509, find='features') + assert isinstance(search_results, dict) + assert search_results['features'][0]['type'] == 'Feature' + assert search_results['features'][0]['geometry']['type'] == 'LineString' + assert len(search_results['features'][0]['geometry']['coordinates']) == 27