{ "cells": [ { "cell_type": "markdown", "id": "84f25893", "metadata": {}, "source": [ "## Connect to OGC API - Features service\n", "\n", "The YIPEEO vector data is exposed as [OGC API\n", "features](https://ogcapi.ogc.org/features/) accessible via\n", "[EODC OGC API - Features](https://features.services.eodc.eu/).\n", "\n", "#### Available YIPEEO collections\n", "\n", "| Data set ID | Description | Access Level |\n", "|------------------------|-------------------------------------------------|-----------|\n", "| pub_yipeeo_yield_fl | Yield estimation and prediction at field level. | Public |\n", "| pub_yipeeo_yield_nuts2 | Yield estimation and prediction at NUTS2 level. | Public |\n", "| prv_yipeeo_yield_field | Yield estimation and prediction at field level. | Protected |\n", "| prv_yipeeo_yield_nuts1 | Yield estimation and prediction at NUTS1 level. | Protected |\n", "| prv_yipeeo_yield_nuts2 | Yield estimation and prediction at NUTS2 level. | Protected |\n", "| prv_yipeeo_yield_nuts3 | Yield estimation and prediction at NUTS3 level. | Protected |\n", "| prv_yipeeo_yield_nuts4 | Yield estimation and prediction at NUTS4 level. | Protected |\n", "| prv_yipeeo_fertilize | Data on fertilizer use at field level. | Protected |\n", "| prv_yipeeo_irrigate | Data on irrigation use at field level. | Protected |\n", "\n", "\n", "The protected collections are only accessible using an EODC account.\n", "This tutorial demonstates the use of the OGC API - Features making use to the\n", "[owslib](https://owslib.readthedocs.io/en/latest/index.html) Python client and\n", "the [EODC SDK](https://pypi.org/project/eodc/) for authentication." ] }, { "cell_type": "code", "execution_count": 1, "id": "51bf9899", "metadata": { "tags": [] }, "outputs": [], "source": [ "import geopandas as gpd\n", "import contextily as cx\n", "from rich.console import Console\n", "\n", "# EODC SDK\n", "from eodc.auth import DaskOIDC\n", "\n", "# OWSLIB\n", "from owslib.ogcapi.features import Features\n", "\n", "# EODC OGC API URL\n", "EODC_OGCAPI_URL = 'https://features.services.eodc.eu/'\n", "\n", "console = Console()" ] }, { "cell_type": "markdown", "id": "6fee8a10", "metadata": {}, "source": [ "## Without Authentication\n", "\n", "Without Authentication, we can still list all available feature collections, as\n", "well as all features from collections which are not protected. But we are not\n", "able to read features from protected collections." ] }, { "cell_type": "code", "execution_count": null, "id": "84a321d6-76ca-4752-b02f-58596a4e8471", "metadata": { "tags": [] }, "outputs": [], "source": [ "# create eodc_ogcapi object without authentication header\n", "eodc_ogcapi = Features(EODC_OGCAPI_URL)\n", "feature_collections = eodc_ogcapi.feature_collections()\n", "console.print(feature_collections)" ] }, { "cell_type": "markdown", "id": "5c77c96d-42a2-4f9c-a445-84aa8618b464", "metadata": {}, "source": [ "Try to get items of a protected collection." ] }, { "cell_type": "code", "execution_count": null, "id": "dc7e51c2-6fce-4135-8107-3459bd62ccd5", "metadata": { "tags": [] }, "outputs": [], "source": [ "collection_id = 'prv_yipeeo_yield_field'\n", "\n", "# This will fail with an '401 Authorization required' error code\n", "items = eodc_ogcapi.collection_items(collection_id)" ] }, { "cell_type": "markdown", "id": "174b21d2", "metadata": {}, "source": [ "## With Authentication\n", "\n", "To read features from protected collections, you need to authenticate with your EODC\n", "credentials. Enter your username, typically the email address you used to sign\n", "up at EODC. A password prompt will be opened automatically.\n", "\n", "After sucessful authentication, the access token will be used as HTTP header for\n", "all future requests using OWSLIB. " ] }, { "cell_type": "code", "execution_count": 4, "id": "ee73deb4", "metadata": {}, "outputs": [], "source": [ "# Enter your username, typically the\n", "# email address you used to sign up at EODC\n", "username = \"firstname.lastname@eodc.eu\" \n", "\n", "conn = DaskOIDC(username)\n", "\n", "headers = {\n", " \"Authorization\": f\"Bearer {conn.token['access_token']}\"\n", "}\n", "\n", "# add HTTP headers to eodc_ogcapi object\n", "eodc_ogcapi = Features(EODC_OGCAPI_URL, headers=headers)" ] }, { "cell_type": "markdown", "id": "b95bf898-5641-4da9-93e3-ac0ad2a7f8e3", "metadata": {}, "source": [ "Print properties of the first item of the given feature collection" ] }, { "cell_type": "code", "execution_count": null, "id": "a03d3bde-ec03-415c-964e-82459df41001", "metadata": { "tags": [] }, "outputs": [], "source": [ "items = eodc_ogcapi.collection_items(collection_id)\n", "console.print(items['features'][0]['properties'])" ] }, { "cell_type": "markdown", "id": "c78ce650", "metadata": {}, "source": [ "## Run a query to extract certain features\n", "Query collection **prv_yipeeo_yield_field** for\n", " - common winter wheat (C1111)\n", " - winter barley (C1310), and \n", " - for a given bounding box near Brno\n", " \n", " and we only want to have a subset of all attributes (properties)\n", " " ] }, { "cell_type": "code", "execution_count": null, "id": "98df6703", "metadata": { "tags": [] }, "outputs": [], "source": [ "bbox = [16.229703926693578,48.713318232352485,17.472665146572798,49.4680057323523]\n", "\n", "selected_props = \"crop_type,crop_id,yield,c_year\"\n", "\n", "cql_filter = \"crop_type='common winter wheat' OR crop_type='winter barley'\"\n", "\n", "# get all items in the yipeeo_yield_fl collection\n", "field_items = eodc_ogcapi.collection_items(\n", " collection_id=collection_id,\n", " bbox=bbox,\n", " limit=2000,\n", " properties=selected_props,\n", " filter=cql_filter,\n", ")\n", "console.print(f\"We found {len(field_items['features'])} items matching the query criteria.\")" ] }, { "cell_type": "markdown", "id": "a4714060", "metadata": {}, "source": [ "## Convert features into Geopandas DataFrame" ] }, { "cell_type": "code", "execution_count": null, "id": "370afa2b", "metadata": { "scrolled": true, "tags": [] }, "outputs": [], "source": [ "df = gpd.GeoDataFrame.from_features(field_items[\"features\"], crs=\"EPSG:4326\")\n", "df " ] }, { "cell_type": "markdown", "id": "fc2f2c13-91d5-4217-a395-cd2cc830f0b0", "metadata": {}, "source": [ "## Plot geometries" ] }, { "cell_type": "code", "execution_count": null, "id": "7980f997-22cb-46eb-b07a-b3b2686cbf3c", "metadata": { "tags": [] }, "outputs": [], "source": [ "ax = df[[\"geometry\"]].plot(\n", " facecolor=\"none\", figsize=(12, 6)\n", ")\n", "cx.add_basemap(ax, crs=df.crs.to_string(), source=cx.providers.OpenStreetMap.Mapnik)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }