{"id":31531519,"url":"https://github.com/hyriver/pygeoogc","last_synced_at":"2025-12-12T01:04:35.366Z","repository":{"id":38020820,"uuid":"278459691","full_name":"hyriver/pygeoogc","owner":"hyriver","description":"A part of HyRiver software stack for accessing ArcGIS RESTful-, WFS-, and WMS-based web services.","archived":false,"fork":false,"pushed_at":"2025-06-25T20:11:13.000Z","size":966,"stargazers_count":11,"open_issues_count":1,"forks_count":8,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-05T08:41:37.213Z","etag":null,"topics":["python","restful","webfeatureservice","webmapservice","webservices"],"latest_commit_sha":null,"homepage":"https://docs.hyriver.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyriver.png","metadata":{"files":{"readme":"README.rst","changelog":"HISTORY.rst","contributing":"CONTRIBUTING.rst","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.rst","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.rst","dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["cheginit"]}},"created_at":"2020-07-09T20:04:11.000Z","updated_at":"2025-06-25T20:11:18.000Z","dependencies_parsed_at":"2023-09-26T03:33:49.702Z","dependency_job_id":"66d66212-df30-40cd-9b54-d09d4f23319c","html_url":"https://github.com/hyriver/pygeoogc","commit_stats":{"total_commits":1132,"total_committers":5,"mean_commits":226.4,"dds":"0.15194346289752647","last_synced_commit":"16ba723d33e9d92d1b936e7de90a56fd544ed934"},"previous_names":["cheginit/pygeoogc"],"tags_count":53,"template":false,"template_full_name":null,"purl":"pkg:github/hyriver/pygeoogc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyriver%2Fpygeoogc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyriver%2Fpygeoogc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyriver%2Fpygeoogc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyriver%2Fpygeoogc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyriver","download_url":"https://codeload.github.com/hyriver/pygeoogc/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyriver%2Fpygeoogc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278254466,"owners_count":25956604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python","restful","webfeatureservice","webmapservice","webservices"],"created_at":"2025-10-04T02:13:05.530Z","updated_at":"2025-10-04T02:13:06.635Z","avatar_url":"https://github.com/hyriver.png","language":"Python","funding_links":["https://github.com/sponsors/cheginit"],"categories":[],"sub_categories":[],"readme":".. image:: https://raw.githubusercontent.com/hyriver/HyRiver-examples/main/notebooks/_static/pygeoogc_logo.png\n    :target: https://github.com/hyriver/HyRiver\n\n|\n\n.. image:: https://joss.theoj.org/papers/b0df2f6192f0a18b9e622a3edff52e77/status.svg\n    :target: https://joss.theoj.org/papers/b0df2f6192f0a18b9e622a3edff52e77\n    :alt: JOSS\n\n|\n\n.. |pygeohydro| image:: https://github.com/hyriver/pygeohydro/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pygeohydro/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |pygeoogc| image:: https://github.com/hyriver/pygeoogc/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pygeoogc/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |pygeoutils| image:: https://github.com/hyriver/pygeoutils/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pygeoutils/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |pynhd| image:: https://github.com/hyriver/pynhd/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pynhd/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |py3dep| image:: https://github.com/hyriver/py3dep/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/py3dep/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |pydaymet| image:: https://github.com/hyriver/pydaymet/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pydaymet/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |pygridmet| image:: https://github.com/hyriver/pygridmet/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pygridmet/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |pynldas2| image:: https://github.com/hyriver/pynldas2/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/pynldas2/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |async| image:: https://github.com/hyriver/async-retriever/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/async-retriever/actions/workflows/test.yml\n    :alt: Github Actions\n\n.. |signatures| image:: https://github.com/hyriver/hydrosignatures/actions/workflows/test.yml/badge.svg\n    :target: https://github.com/hyriver/hydrosignatures/actions/workflows/test.yml\n    :alt: Github Actions\n\n================ ====================================================================\nPackage          Description\n================ ====================================================================\nPyNHD_           Navigate and subset NHDPlus (MR and HR) using web services\nPy3DEP_          Access topographic data through National Map's 3DEP web service\nPyGeoHydro_      Access NWIS, NID, WQP, eHydro, NLCD, CAMELS, and SSEBop databases\nPyDaymet_        Access daily, monthly, and annual climate data via Daymet\nPyGridMET_       Access daily climate data via GridMET\nPyNLDAS2_        Access hourly NLDAS-2 data via web services\nHydroSignatures_ A collection of tools for computing hydrological signatures\nAsyncRetriever_  High-level API for asynchronous requests with persistent caching\nPyGeoOGC_        Send queries to any ArcGIS RESTful-, WMS-, and WFS-based services\nPyGeoUtils_      Utilities for manipulating geospatial, (Geo)JSON, and (Geo)TIFF data\n================ ====================================================================\n\n.. _PyGeoHydro: https://github.com/hyriver/pygeohydro\n.. _AsyncRetriever: https://github.com/hyriver/async-retriever\n.. _PyGeoOGC: https://github.com/hyriver/pygeoogc\n.. _PyGeoUtils: https://github.com/hyriver/pygeoutils\n.. _PyNHD: https://github.com/hyriver/pynhd\n.. _Py3DEP: https://github.com/hyriver/py3dep\n.. _PyDaymet: https://github.com/hyriver/pydaymet\n.. _PyGridMET: https://github.com/hyriver/pygridmet\n.. _PyNLDAS2: https://github.com/hyriver/pynldas2\n.. _HydroSignatures: https://github.com/hyriver/hydrosignatures\n\nPyGeoOGC: Retrieve Data from RESTful, WMS, and WFS Services\n-----------------------------------------------------------\n\n.. image:: https://img.shields.io/pypi/v/pygeoogc.svg\n    :target: https://pypi.python.org/pypi/pygeoogc\n    :alt: PyPi\n\n.. image:: https://img.shields.io/conda/vn/conda-forge/pygeoogc.svg\n    :target: https://anaconda.org/conda-forge/pygeoogc\n    :alt: Conda Version\n\n.. image:: https://codecov.io/gh/hyriver/pygeoogc/branch/main/graph/badge.svg\n    :target: https://codecov.io/gh/hyriver/pygeoogc\n    :alt: CodeCov\n\n.. image:: https://img.shields.io/pypi/pyversions/pygeoogc.svg\n    :target: https://pypi.python.org/pypi/pygeoogc\n    :alt: Python Versions\n\n.. image:: https://static.pepy.tech/badge/pygeoogc\n    :target: https://pepy.tech/project/pygeoogc\n    :alt: Downloads\n\n|\n\n.. image:: https://img.shields.io/badge/security-bandit-green.svg\n    :target: https://github.com/PyCQA/bandit\n    :alt: Security Status\n\n.. image:: https://www.codefactor.io/repository/github/hyriver/pygeoogc/badge\n   :target: https://www.codefactor.io/repository/github/hyriver/pygeoogc\n   :alt: CodeFactor\n\n.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json\n    :target: https://github.com/astral-sh/ruff\n    :alt: Ruff\n\n.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit\u0026logoColor=white\n    :target: https://github.com/pre-commit/pre-commit\n    :alt: pre-commit\n\n.. image:: https://mybinder.org/badge_logo.svg\n    :target: https://mybinder.org/v2/gh/hyriver/HyRiver-examples/main?urlpath=lab/tree/notebooks\n    :alt: Binder\n\n|\n\nFeatures\n--------\n\nPyGeoOGC is a part of `HyRiver \u003chttps://github.com/hyriver/HyRiver\u003e`__ software stack that\nis designed to aid in hydroclimate analysis through web services. This package provides\ngeneral interfaces to web services that are based on\n`ArcGIS RESTful \u003chttps://en.wikipedia.org/wiki/Representational_state_transfer\u003e`__,\n`WMS \u003chttps://en.wikipedia.org/wiki/Web_Map_Service\u003e`__, and\n`WFS \u003chttps://en.wikipedia.org/wiki/Web_Feature_Service\u003e`__. Although\nall these web services have limits on the number of features per request (e.g., 1000\nobject IDs for a RESTful request or 8 million pixels for a WMS request), PyGeoOGC, first, divides\nthe large requests into smaller chunks, and then returns the merged results.\n\nMoreover, under the hood, PyGeoOGC uses\n`AsyncRetriever \u003chttps://github.com/hyriver/async-retriever\u003e`__\nfor making requests asynchronously with persistent caching. This improves the\nreliability and speed of data retrieval significantly. AsyncRetriever caches all request/response\npairs and upon making an already cached request, it will retrieve the responses from the cache\nif the server's response is unchanged.\n\nYou can control the request/response caching behavior and verbosity of the package\nby setting the following environment variables:\n\n* ``HYRIVER_CACHE_NAME``: Path to the caching SQLite database for asynchronous HTTP\n  requests. It defaults to ``./cache/aiohttp_cache.sqlite``\n* ``HYRIVER_CACHE_NAME_HTTP``: Path to the caching SQLite database for HTTP requests.\n  It defaults to ``./cache/http_cache.sqlite``\n* ``HYRIVER_CACHE_EXPIRE``: Expiration time for cached requests in seconds. It defaults to\n  one week.\n* ``HYRIVER_CACHE_DISABLE``: Disable reading/writing from/to the cache. The default is false.\n* ``HYRIVER_SSL_CERT``: Path to a SSL certificate file.\n\nFor example, in your code before making any requests you can do:\n\n.. code-block:: python\n\n    import os\n\n    os.environ[\"HYRIVER_CACHE_NAME\"] = \"path/to/aiohttp_cache.sqlite\"\n    os.environ[\"HYRIVER_CACHE_NAME_HTTP\"] = \"path/to/http_cache.sqlite\"\n    os.environ[\"HYRIVER_CACHE_EXPIRE\"] = \"3600\"\n    os.environ[\"HYRIVER_CACHE_DISABLE\"] = \"true\"\n    os.environ[\"HYRIVER_SSL_CERT\"] = \"path/to/cert.pem\"\n\nThere is also an inventory of URLs for some of these web services in form of a class called\n``ServiceURL``. These URLs are in four categories: ``ServiceURL().restful``,\n``ServiceURL().wms``, ``ServiceURL().wfs``, and ``ServiceURL().http``. These URLs provide you\nwith some examples of the services that PyGeoOGC supports. If you have success using PyGeoOGC with a web\nservice please consider submitting a request to be added to this URL inventory. You can get all\nthe URLs in the ``ServiceURL`` class by just printing it ``print(ServiceURL())``.\n\nPyGeoOGC has three main classes:\n\n* ``ArcGISRESTful``: This class can be instantiated by providing the target layer URL.\n  For example, for getting Watershed Boundary Data we can use ``ServiceURL().restful.wbd``.\n  By looking at the web service's\n  `website \u003chttps://hydro.nationalmap.gov/arcgis/rest/services/wbd/MapServer\u003e`_\n  we see that there are nine layers. For example, 1 for 2-digit HU (Region), 6 for 12-digit HU\n  (Subregion), and so on. We can pass the URL to the target layer directly, like this\n  ``f\"{ServiceURL().restful.wbd}/6\"`` or as a separate argument via ``layer``.\n\n  Afterward, we request for the data in two steps. First, we need to get\n  the target object IDs using ``oids_bygeom`` (within a geometry), ``oids_byfield`` (specific\n  field IDs), or ``oids_bysql`` (any valid SQL 92 WHERE clause) class methods. Then, we can get\n  the target features using ``get_features`` class method. The returned response can be converted\n  into a ``geopandas.GeoDataFrame`` using ``json2geodf`` function from\n  `PyGeoUtils \u003chttps://github.com/hyriver/pygeoutils\u003e`__.\n\n* ``WMS``: Instantiation of this class requires at least 3 arguments: service URL, layer\n  name(s), and output format. Additionally, target CRS and the web service version can be provided.\n  Upon instantiation, we can use ``getmap_bybox`` method class to get the target raster data\n  within a bounding box. The box can be in any valid CRS and if it is different from the default\n  CRS, ``EPSG:4326``, it should be passed using ``box_crs`` argument. The service response can be\n  converted into a ``xarray.Dataset`` using ``gtiff2xarray`` function from PyGeoUtils.\n\n* ``WFS``: Instantiation of this class is similar to ``WMS``. The only difference is that\n  only one layer name can be passed. Upon instantiation there are three ways to get the data:\n\n  - ``getfeature_bybox``: Get all the target features within a bounding box in any valid CRS.\n  - ``getfeature_byid``: Get all the target features based on the IDs. Note that two arguments\n    should be provided: ``featurename``, and ``featureids``. You can get a list of valid feature\n    names using ``get_validnames`` class method.\n  - ``getfeature_byfilter``: Get the data based on any valid\n    `CQL \u003chttps://docs.geoserver.org/latest/en/user/tutorials/cql/cql_tutorial.html\u003e`__ filter.\n\n  You can convert the returned response of this function to a ``GeoDataFrame`` using ``json2geodf``\n  function from PyGeoUtils package.\n\nPyGeoOGC also includes several utilities:\n\n- ``streaming_download`` for downloading large files in parallel and in chunks, efficiently.\n- ``traverse_json`` for traversing a nested JSON object.\n- ``match_crs`` for reprojecting a geometry or bounding box to any valid CRS.\n\nYou can find some example notebooks `here \u003chttps://github.com/hyriver/HyRiver-examples\u003e`__.\n\nFurthermore, you can also try using PyGeoOGC without installing\nit on your system by clicking on the binder badge. A Jupyter Lab\ninstance with the HyRiver stack pre-installed will be launched in your web browser, and you\ncan start coding!\n\nMoreover, requests for additional functionalities can be submitted via\n`issue tracker \u003chttps://github.com/hyriver/pygeoogc/issues\u003e`__.\n\nCitation\n--------\nIf you use any of HyRiver packages in your research, we appreciate citations:\n\n.. code-block:: bibtex\n\n    @article{Chegini_2021,\n        author = {Chegini, Taher and Li, Hong-Yi and Leung, L. Ruby},\n        doi = {10.21105/joss.03175},\n        journal = {Journal of Open Source Software},\n        month = {10},\n        number = {66},\n        pages = {1--3},\n        title = {{HyRiver: Hydroclimate Data Retriever}},\n        volume = {6},\n        year = {2021}\n    }\n\nInstallation\n------------\n\nYou can install PyGeoOGC using ``pip``:\n\n.. code-block:: console\n\n    $ pip install pygeoogc\n\nAlternatively, PyGeoOGC can be installed from the ``conda-forge`` repository\nusing `Conda \u003chttps://docs.conda.io/en/latest/\u003e`__\nor `Mamba \u003chttps://github.com/conda-forge/miniforge\u003e`__:\n\n.. code-block:: console\n\n    $ conda install -c conda-forge pygeoogc\n\nQuick start\n-----------\n\nWe can access\n`NHDPlus HR \u003chttps://edits.nationalmap.gov/arcgis/rest/services/NHDPlus_HR/NHDPlus_HR/MapServer\u003e`__\nvia RESTful service,\n`National Wetlands Inventory \u003chttps://www.fws.gov/wetlands/\u003e`__ from WMS, and\n`FEMA National Flood Hazard \u003chttps://www.fema.gov/national-flood-hazard-layer-nfhl\u003e`__\nvia WFS. The output for these functions are of type ``requests.Response`` that\ncan be converted to ``GeoDataFrame`` or ``xarray.Dataset`` using\n`PyGeoUtils \u003chttps://github.com/hyriver/pygeoutils\u003e`__.\n\nLet's start the National Map's NHDPlus HR web service. We can query the flowlines that are\nwithin a geometry as follows:\n\n.. code-block:: python\n\n    from pygeoogc import ArcGISRESTful, WFS, WMS, ServiceURL\n    import pygeoutils as geoutils\n    from pynhd import NLDI\n\n    basin_geom = NLDI().get_basins(\"01031500\").geometry[0]\n\n    hr = ArcGISRESTful(ServiceURL().restful.nhdplushr, 2, outformat=\"json\")\n\n    resp = hr.get_features(hr.oids_bygeom(basin_geom, 4326))\n    flowlines = geoutils.json2geodf(resp)\n\nNote ``oids_bygeom`` has three additional arguments: ``sql_clause``, ``spatial_relation``,\nand ``distance``. We can use ``sql_clause`` for passing any valid SQL WHERE clauses and\n``spatial_relation`` for specifying the target predicate such as\nintersect, contain, cross, etc. The default predicate is intersect\n(``esriSpatialRelIntersects``). Additionally, we can use ``distance`` for specifying the buffer\ndistance from the input geometry for getting features.\n\nWe can also submit a query based on IDs of any valid field in the database. If the measure\nproperty is desired you can pass ``return_m`` as ``True`` to the ``get_features`` class method:\n\n.. code-block:: python\n\n    oids = hr.oids_byfield(\"PERMANENT_IDENTIFIER\", [\"103455178\", \"103454362\", \"103453218\"])\n    resp = hr.get_features(oids, return_m=True)\n    flowlines = geoutils.json2geodf(resp)\n\nAdditionally, any valid SQL 92 WHERE clause can be used. For more details look\n`here \u003chttps://developers.arcgis.com/rest/services-reference/query-feature-service-.htm#ESRI_SECTION2_07DD2C5127674F6A814CE6C07D39AD46\u003e`__.\nFor example, let's limit our first request to only include catchments with\nareas larger than 0.5 sqkm.\n\n.. code-block:: python\n\n    oids = hr.oids_bygeom(basin_geom, geo_crs=4326, sql_clause=\"AREASQKM \u003e 0.5\")\n    resp = hr.get_features(oids)\n    catchments = geoutils.json2geodf(resp)\n\nA WMS-based example is shown below:\n\n.. code-block:: python\n\n    wms = WMS(\n        ServiceURL().wms.fws,\n        layers=\"0\",\n        outformat=\"image/tiff\",\n        crs=3857,\n    )\n    r_dict = wms.getmap_bybox(\n        basin_geom.bounds,\n        1e3,\n        box_crs=4326,\n    )\n    wetlands = geoutils.gtiff2xarray(r_dict, basin_geom, 4326)\n\nQuery from a WFS-based web service can be done either within a bounding box or using\nany valid `CQL filter \u003chttps://docs.geoserver.org/stable/en/user/tutorials/cql/cql_tutorial.html\u003e`__.\n\n.. code-block:: python\n\n    wfs = WFS(\n        ServiceURL().wfs.fema,\n        layer=\"public_NFHL:Base_Flood_Elevations\",\n        outformat=\"esrigeojson\",\n        crs=4269,\n    )\n    r = wfs.getfeature_bybox(basin_geom.bounds, box_crs=4326)\n    flood = geoutils.json2geodf(r.json(), 4269, 4326)\n\n    layer = \"wmadata:huc08\"\n    wfs = WFS(\n        ServiceURL().wfs.waterdata,\n        layer=layer,\n        outformat=\"application/json\",\n        version=\"2.0.0\",\n        crs=4269,\n    )\n    r = wfs.getfeature_byfilter(f\"huc8 LIKE '13030%'\")\n    huc8 = geoutils.json2geodf(r.json(), 4269, 4326)\n\n.. image:: https://raw.githubusercontent.com/hyriver/HyRiver-examples/main/notebooks/_static/sql_clause.png\n    :target: https://github.com/hyriver/HyRiver-examples/blob/main/notebooks/webservices.ipynb\n\n\nContributing\n------------\n\nContributions are appreciated and very welcomed. Please read\n`CONTRIBUTING.rst \u003chttps://github.com/hyriver/pygeoogc/blob/main/CONTRIBUTING.rst\u003e`__\nfor instructions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyriver%2Fpygeoogc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyriver%2Fpygeoogc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyriver%2Fpygeoogc/lists"}