diff --git a/jupyter-notebooks/api_guides/features_api/planet_sdk_features_demo.ipynb b/jupyter-notebooks/api_guides/features_api/planet_sdk_features_demo.ipynb new file mode 100644 index 00000000..a8533306 --- /dev/null +++ b/jupyter-notebooks/api_guides/features_api/planet_sdk_features_demo.ipynb @@ -0,0 +1,794 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "77185d9d", + "metadata": {}, + "source": [ + "# Planet Features API Python Client Introduction\n" + ] + }, + { + "cell_type": "markdown", + "id": "c5e76294", + "metadata": {}, + "source": [ + "This tutorial is an introduction to [Planet's](https://www.planet.com) Features API using the official [Python client](https://github.com/planetlabs/planet-client-python), the `Planet` module. The Features API is used to create *Collections* made up of *Features* that follow [OGC-compliant features standards](https://ogcapi.ogc.org/features/). The features are stored as GeoJson format FeatureCollections, and will be then be available to use across the Planet APIs or platform, including in Planet Explorer and Features Manager. Your features are referred to as *items* within the FeatureCollection by the API and API documentation.\n", + "\n", + "## Requirements\n", + "\n", + "An account on the [Planet Platform](https://www.planet.com/account/) is required to access any of Planet's API's. If you are not logged in, you will be prompted to do so below in the *SDK Authentication* section.\n", + "\n", + "## Useful links \n", + "* [Planet SDK for Python](https://planet-sdk-for-python.readthedocs.io/en/stable/get-started/quick-start-guide/)\n", + "* [Planet Python Client Repo](https://github.com/planetlabs/planet-client-python)\n", + "* [Planet Features API Documentation](https://docs.planet.com/develop/apis/features/)" + ] + }, + { + "cell_type": "markdown", + "id": "1be92e24", + "metadata": {}, + "source": [ + "The basic workflow for interaction with the Features API is:\n", + "1. Define Feature(s) through filepath or text.\n", + "2. Create a Collection with a unique name.\n", + "3. Add features to the collection.\n", + "4. Use feature reference code 'pl:ref' as geometry input in other API calls.\n", + "\n", + "Collections and the Features they hold will be viewable in the Planet Platform [Features Manager](https://www.planet.com/features/). You should be able to see all the Features your org has access to.\n", + "

\n", + "\n", + "Using the workflow in this tutorial will walk you through using a predefined AOI in Cairo, Egypt around Cairo Lake as the feature for our Collection. You may also input your own Feature Collection from an area of your choice." + ] + }, + { + "cell_type": "markdown", + "id": "90c47ef3", + "metadata": {}, + "source": [ + "____" + ] + }, + { + "cell_type": "markdown", + "id": "f4d93f03", + "metadata": {}, + "source": [ + "## Set up\n", + "\n", + "In order to interact with the Planet API using the Python client, we need to import the necessary packages and authenticate our Planet account credentials." + ] + }, + { + "cell_type": "markdown", + "id": "3c69445b", + "metadata": {}, + "source": [ + "### Imports" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "6b967c46", + "metadata": {}, + "outputs": [], + "source": [ + "import geopandas as gpd\n", + "import json\n", + "import pathlib\n", + "import planet\n", + "from datetime import datetime\n", + "from planet import Auth, Planet, Session, order_request, data_filter, reporting\n", + "from planet.geojson import as_ref" + ] + }, + { + "cell_type": "markdown", + "id": "8eb30bd9", + "metadata": {}, + "source": [ + "### SDK Authentication\n", + "\n", + "Your Planet login is used to authenticate and activate the Python SDK. You will be prompted via a link below to login and confirm on the page that the code displayed matches the authorization code printed. If this is your first time accessing the Planet SDK, you will also be prompted first to authorize the SDK access to your Planet account. \n", + "If you would like to know more, please visit the [authentication documentation](https://docs.planet.com/develop/authentication)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "481bb763", + "metadata": {}, + "outputs": [], + "source": [ + "# OAuth2 python client authentication\n", + "# If you are not already logged in, this will prompt you to open a web browser to log in.\n", + "\n", + "auth = Auth.from_profile('planet-user', save_state_to_storage=False)\n", + "auth.ensure_initialized(allow_open_browser=True, allow_tty_prompt=True)\n", + "\n", + "session = Session(auth)\n", + "pl = Planet(session)" + ] + }, + { + "cell_type": "markdown", + "id": "960dec0b", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "id": "faf6ab86", + "metadata": {}, + "source": [ + "### Define Features\n", + "\n", + "First, define the FeatureCollection you wish to post to the FeaturesAPI. Only Polygon and MultiPolygon Feature types are supported.\n", + "\n", + "The features must follow the same rules for AOI geometry used in other Planet APIs, including:\n", + "\n", + "- Standard GeoJSON FeatureCollection format.\n", + "- Must use WGS84/EPSG:4326 projection.\n", + "- Be 2 dimensional (No Z coordinates/elevation)\n", + "- Contain 1500 vertices or *less* per feature.\n", + "\n", + "Full feature rules may be found [here](https://docs.planet.com/develop/apis/features/uploading-and-validating-features/#rules-for-creating-a-feature). \n", + "

\n", + "Below we have defined a FeatureCollection of two areas in Cairo, Egypt. You may use this FeatureCollection to follow along with the tutorial, define your own, or import one from a GeoJSON filepath." + ] + }, + { + "cell_type": "markdown", + "id": "0c215ebb", + "metadata": {}, + "source": [ + "You have a few options to define features to post to your Collections:\n", + "- The simplest option is to use a predefined FeatureCollection, so that the Features API can separate each feature into individual items for you.\n", + "- You may alternatively pass in just the geometries from feature collections. \n", + " - There is a free tool [geojson.io](https://geojson.io/) that will allow you to create geometries and FeatureCollections by hand. You can also draw and download custom AOI geojson's from [Planet Explorer](https://www.planet.com/explorer/)." + ] + }, + { + "cell_type": "markdown", + "id": "ab8ef406", + "metadata": {}, + "source": [ + "#### Feature Properties\n", + "\n", + "While you only require geometry for Features to be used by the Features API, you may notice that the example FeatureCollection below has additional `properties` beyond the title. If a feature is uploaded without specifying the `property_id` parameter (more about this later), all properties of the feature are retained in the item. You can retain extra properties and set your Feature's `id` with an 'id' key and leaving the `property_id` parameter as None. \n", + "\n", + "**Note** You may optionally give your feature a display name in the Features Manager web interface with a `title` key in the features properties. When you upload a feature, it is not required to have a title. Your feature will still display in the [Features Manager](https://www.planet.com/features/) GUI (displayed as _Untitled Feature_), and function properly in Planet's APIs without a 'Feature Name'.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "33202e83", + "metadata": {}, + "outputs": [], + "source": [ + "lake_poly = [[[31.23905453, 29.99579775], [31.26630889, 29.99579775], [31.26630889, 30.01908084], [31.23905453, 30.01908084], [31.23905453, 29.99579775]]]\n", + "institute_poly = [[[31.23344423, 30.05109414], [31.25491533, 30.05109414], [31.25491533, 30.06461941], [31.23344423, 30.06461941], [31.23344423, 30.05109414]]]\n", + "\n", + "cairo_fc = {\n", + " \"type\": \"FeatureCollection\",\n", + " \"features\": [\n", + " {\n", + " \"id\": \"0\",\n", + " \"type\": \"Feature\",\n", + " \"properties\": {\n", + " \"title\": \"lake_area\",\n", + " \"name_str\": \"area_1\",\n", + " \"extra_property_1\": 'extra property 1 here',\n", + " \"extra_property_2\": 'extra property 2 here'},\n", + " \"geometry\": {\"coordinates\": lake_poly, \"type\": \"Polygon\"},\n", + " },\n", + " {\n", + " \"id\": \"1\",\n", + " \"type\": \"Feature\",\n", + " \"properties\": {\n", + " \"title\": \"institute_area\",\n", + " \"name_str\": \"area_2\",\n", + " \"extra_property_1\": 'extra property 1 here',\n", + " \"extra_property_2\": 'extra property 2 here'},\n", + " \"geometry\": {\"coordinates\": institute_poly, \"type\": \"Polygon\"},\n", + " },\n", + "]}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4f8ce61", + "metadata": {}, + "outputs": [], + "source": [ + "# Read your geojson path, then send it to a geo_dict.\n", + "geojson_path = 'PATH TO YOUR GEOJSON FILE'\n", + "\n", + "with open(geojson_path, 'r') as file:\n", + " local_fc = json.load(file)" + ] + }, + { + "cell_type": "markdown", + "id": "809f257d", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "id": "70faedbb", + "metadata": {}, + "source": [ + "### Name and create your FeatureCollection in the Features API\n", + "\n", + "Before you upload your FeatureCollection items, you need to create the Collection using the Features API. If you already have an existing collection and have its id, you may skip creating a new Collection.\n", + "\n", + "Set your `collection_title`, which will serve as the title or name of the whole FeatureCollection. You may optionally set a description for your Collection. `pl.features.create_collection` will create your Collection and return its newly created `collection_id`, which is needed to add items to the Collection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f925cb6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'cairo_areas-Kr7JYmq'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_collection_id = pl.features.create_collection(title='cairo_areas', description='FeatureCollection of two areas in Cairo, Egypt')\n", + "new_collection_id" + ] + }, + { + "cell_type": "markdown", + "id": "63aa9b82", + "metadata": {}, + "source": [ + "### Post Features to your Collection\n", + "\n", + "After the Collection is created, you may post your features from the FeatureCollection we defined above. \n", + "

\n", + "The `property_id` is optional, it refers to which key from the `properties` block of the supplied feature(s) to use in the `id` for the collection. This gives you some control of the identifier for items without having to change the name of a key to id. Note that an alphanumeric string will be added onto the end of the id even if you set the key to use, to ensure unique ids for all items.\n", + "

\n", + "Without the `property_id` specified, a random string is generated for a features' id, unless the features has a distinct `id` key. \n", + "

\n", + "The example FeatureCollection has some extra properties like `name_str` that can be used as the id." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "4855833d", + "metadata": {}, + "outputs": [], + "source": [ + "# Optional\n", + "property_id = None\n", + "\n", + "new_items = pl.features.add_items(collection_id=new_collection_id, feature=cairo_fc, property_id=property_id)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "b10dafc8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['pl:features/my/cairo_areas-Kr7JYmq/0-gAbBZDk',\n", + " 'pl:features/my/cairo_areas-Kr7JYmq/1-owL5RyP']" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_items" + ] + }, + { + "cell_type": "markdown", + "id": "dbb6594f", + "metadata": {}, + "source": [ + "`add_items` returned a list of strings, which are the Feature Reference IDs of the items we just added to the collection. These are used in the `geometry` parameter for Orders and Subscriptions. They are accessible from the `pl:ref` key of an item in the Features API. Before we order imagery with these, we will first explore the other functionalities of the Features python client." + ] + }, + { + "cell_type": "markdown", + "id": "eaad89f4", + "metadata": {}, + "source": [ + "____" + ] + }, + { + "cell_type": "markdown", + "id": "3bcf7ccd", + "metadata": {}, + "source": [ + "### Access your feature Collections from the Features API" + ] + }, + { + "cell_type": "markdown", + "id": "e94f5cb5", + "metadata": {}, + "source": [ + "Basic information (title, description, extent, etc.) about all the feature collections you have access to is available with `list_collections()`" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "6fff398e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'id': 'cairo_areas-Kr7JYmq',\n", + " 'title': 'cairo_areas',\n", + " 'description': 'FeatureCollection of two areas in Cairo, Egypt',\n", + " 'item_type': 'feature',\n", + " 'created': '2025-12-19T23:22:29Z',\n", + " 'updated': '2025-12-19T23:22:33Z',\n", + " 'extent': {'spatial': {'bbox': [[31.23344423,\n", + " 29.99579775,\n", + " 31.26630889,\n", + " 30.06461941]]}},\n", + " 'links': [{'href': 'https://api.planet.com/features/v1/ogc/my/collections/cairo_areas-Kr7JYmq',\n", + " 'rel': 'self',\n", + " 'title': 'This collection',\n", + " 'type': 'application/json'},\n", + " {'href': 'https://api.planet.com/features/v1/ogc/my/collections/cairo_areas-Kr7JYmq/items',\n", + " 'rel': 'features',\n", + " 'title': 'Features',\n", + " 'type': 'application/json'}],\n", + " 'feature_count': 2,\n", + " 'area': 9890943.929543883,\n", + " 'title_property': None,\n", + " 'description_property': None,\n", + " 'properties': {},\n", + " 'permissions': {'can_write': True, 'shared': False, 'is_owner': True},\n", + " 'ownership': {'owner_id': 820676, 'org_id': 776979},\n", + " 'pl:ref': 'pl:features/my/cairo_areas-Kr7JYmq'}]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "collections_list = list(pl.features.list_collections())\n", + "collections_list" + ] + }, + { + "cell_type": "markdown", + "id": "d6864356", + "metadata": {}, + "source": [ + "We will use the collection_id of the Collection we created above, `new_collection_id` to list all of its items with `list_items()`:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "9c06b2a3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': 'Feature',\n", + " 'id': '1',\n", + " 'properties': {'title': 'institute_area',\n", + " 'name_str': 'area_2',\n", + " 'extra_property_1': 'extra property 1 here',\n", + " 'extra_property_2': 'extra property 2 here',\n", + " 'pl:ref': 'pl:features/my/cairo_areas-Kr7JYmq/1-owL5RyP',\n", + " 'pl:area': 3104292.7715780144},\n", + " 'geometry': {'type': 'Polygon',\n", + " 'coordinates': [[[31.23344423, 30.05109414],\n", + " [31.25491533, 30.05109414],\n", + " [31.25491533, 30.06461941],\n", + " [31.23344423, 30.06461941],\n", + " [31.23344423, 30.05109414]]]}},\n", + " {'type': 'Feature',\n", + " 'id': '0',\n", + " 'properties': {'title': 'lake_area',\n", + " 'name_str': 'area_1',\n", + " 'extra_property_1': 'extra property 1 here',\n", + " 'extra_property_2': 'extra property 2 here',\n", + " 'pl:ref': 'pl:features/my/cairo_areas-Kr7JYmq/0-gAbBZDk',\n", + " 'pl:area': 6786651.157965869},\n", + " 'geometry': {'type': 'Polygon',\n", + " 'coordinates': [[[31.23905453, 29.99579775],\n", + " [31.26630889, 29.99579775],\n", + " [31.26630889, 30.01908084],\n", + " [31.23905453, 30.01908084],\n", + " [31.23905453, 29.99579775]]]}}]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "item_list = list(pl.features.list_items(new_collection_id))\n", + "item_list" + ] + }, + { + "cell_type": "markdown", + "id": "6e981de2", + "metadata": {}, + "source": [ + "To get a singular item from a feature collection, you need the `collection_id` as well as the `feature_id` itself. We will be reusing the `collection_id` from before, and using the first item in our `item_list`." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "a69f7322", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'type': 'Feature',\n", + " 'id': '1',\n", + " 'properties': {'title': 'institute_area',\n", + " 'name_str': 'area_2',\n", + " 'extra_property_1': 'extra property 1 here',\n", + " 'extra_property_2': 'extra property 2 here',\n", + " 'pl:ref': 'pl:features/my/cairo_areas-Kr7JYmq/1-owL5RyP',\n", + " 'pl:area': 3104292.7715780144},\n", + " 'geometry': {'type': 'Polygon',\n", + " 'coordinates': [[[31.23344423, 30.05109414],\n", + " [31.25491533, 30.05109414],\n", + " [31.25491533, 30.06461941],\n", + " [31.23344423, 30.06461941],\n", + " [31.23344423, 30.05109414]]]},\n", + " 'links': [{'rel': 'self',\n", + " 'href': 'https://api.planet.com/features/v1/ogc/my/collections/cairo_areas-Kr7JYmq/items/1-owL5RyP'},\n", + " {'rel': 'collection',\n", + " 'href': 'https://api.planet.com/features/v1/ogc/my/collections/cairo_areas-Kr7JYmq'}]}" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "feature_id = item_list[0]['id']\n", + "pl.features.get_item(new_collection_id, feature_id)" + ] + }, + { + "cell_type": "markdown", + "id": "d8f60483", + "metadata": {}, + "source": [ + "___" + ] + }, + { + "cell_type": "markdown", + "id": "40384055", + "metadata": {}, + "source": [ + "### Deleting Collections\n", + "\n", + "Using the `collection_id` you may delete a collection using `delete_collection()`. Be careful when you do this, as there is no confirmation output from this method, and the collection will just be deleted." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b61da442", + "metadata": {}, + "outputs": [], + "source": [ + "# WARNING: This permanently deletes the collection.\n", + "collection_id = ''\n", + "pl.features.delete_collection(collection_id)" + ] + }, + { + "cell_type": "markdown", + "id": "5d2b33e6", + "metadata": {}, + "source": [ + "_____" + ] + }, + { + "cell_type": "markdown", + "id": "861cc6e6", + "metadata": {}, + "source": [ + "# Using Feature References as input geometries\n", + "\n", + "The Feature Reference IDs, `'pl:ref'` property of a feature is used in other Planet APIs as the geometry parameter instead of having the user track bounding box and geometry variables. Planet `Data`, `Orders`, and `Subscriptions` APIs are all able to make use of a Feature Reference ID. \n", + "\n", + "Feature Reference IDs are submitted in the `geometry` argument in API calls as a dictionary:\n", + "```python\n", + "geometry = {\n", + " 'type': 'ref',\n", + " 'content': 'pl:features/my//'\n", + "}\n", + "```\n", + "We can construct this with a helpful function we imported from planet.geojson, `as_ref`, that will return our Feature Reference ID as the dictionary. \n", + "\n", + "Provided below is consolidated code to use the SDK to get a `pl:ref` from the Features API, use it in a Data API query, and then submit an order request for one item_id clipped to the feature's geometry. If you are unfamiliar with the mechanics of the `order_request` functions of the SDK, the [planet_sdk_orders_demo](https://github.com/planetlabs/notebooks/blob/master/jupyter-notebooks/api_guides/orders_api/planet_sdk_orders_demo.ipynb) notebook will walk you through how to create and submit Orders with the Planet Python SDK." + ] + }, + { + "cell_type": "markdown", + "id": "7df66208", + "metadata": {}, + "source": [ + "#### SDK Order workflow:\n", + "1. Get Feature Reference ID from Features API and use `as_ref` to format it for use in the variable `geometry_ref`.\n", + "2. Run Data API search using `geometry_ref`.\n", + "3. Submit order_request to the Orders API using the item_id of the first item returned for our search and `geometry_ref` as the input for our clip tool." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "c70b7db8", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'type': 'ref', 'content': 'pl:features/my/cairo_areas-Kr7JYmq/1-owL5RyP'}" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# List all your collections\n", + "collections_list = list(pl.features.list_collections())\n", + "\n", + "# Get the id of the first collection in your list\n", + "collection_id = collections_list[0]['id']\n", + "\n", + "collection_items = list(pl.features.list_items(collection_id))\n", + "feature_ref = collection_items[0]['properties']['pl:ref']\n", + "geometry_ref = as_ref(feature_ref)\n", + "geometry_ref" + ] + }, + { + "cell_type": "markdown", + "id": "4472ade0", + "metadata": {}, + "source": [ + "To use your Feature Reference ID in Data API, input it as the `geometry` param in `data.create_search`, and not as a geometry filter." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "e57ba8c5", + "metadata": {}, + "outputs": [], + "source": [ + "# Search for PlanetScope ortho_analytic_4b assets within a date range and geometry\n", + "name = 'geometry_ref_search'\n", + "item_types = ['PSScene']\n", + "asset_types = ['ortho_analytic_4b']\n", + "start_time = datetime.fromisoformat('2022-05-01T00:00:00Z')\n", + "end_time = datetime.fromisoformat('2022-05-02T00:00:00Z')\n", + "drf = data_filter.date_range_filter('published', gte=start_time, lte=end_time)\n", + "\n", + "search_filter = data_filter.and_filter([drf])\n", + "\n", + "\n", + "# Create and run the search:\n", + "pl_search = pl.data.create_search(\n", + " item_types=item_types,\n", + " search_filter=search_filter,\n", + " name=name,\n", + " geometry=geometry_ref)\n", + "\n", + "search_results = pl.data.run_search(pl_search['id'])\n", + "search_items = list(search_results)\n", + "\n", + "# Get the id of the first item in your search results\n", + "item_id = search_items[0]['id']" + ] + }, + { + "cell_type": "markdown", + "id": "8b205182", + "metadata": {}, + "source": [ + "Order request, clipped to the feature:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "0912c4a8", + "metadata": {}, + "outputs": [], + "source": [ + "product_bundle = 'analytic_udm2'\n", + "\n", + "order_product = order_request.product(\n", + " item_ids=[item_id], product_bundle=product_bundle, item_type = item_types[0])\n", + "tools = [order_request.clip_tool(feature_ref)]" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "8040f22f", + "metadata": {}, + "outputs": [], + "source": [ + "name = 'geometry_ref_order'\n", + "\n", + "order_dict = planet.order_request.build_request(name, products = [order_product], tools=tools)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "0e699260", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'name': 'geometry_ref_order',\n", + " 'products': [{'item_ids': ['20220501_074035_74_2420'],\n", + " 'item_type': 'PSScene',\n", + " 'product_bundle': 'analytic_udm2'}],\n", + " 'tools': [{'clip': {'aoi': {'type': 'ref',\n", + " 'content': 'pl:features/my/cairo_areas-Kr7JYmq/1-owL5RyP'}}}]}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "order_dict" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "baf6af91", + "metadata": {}, + "outputs": [], + "source": [ + "order = pl.orders.create_order(request=order_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "3a4f2a85", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'_links': {'_self': 'https://api.planet.com/compute/ops/orders/v2/25a7854a-554b-4f4c-b664-9f5ec2b1aef9'},\n", + " 'created_on': '2025-12-19T23:22:54.22275Z',\n", + " 'error_hints': [],\n", + " 'id': '25a7854a-554b-4f4c-b664-9f5ec2b1aef9',\n", + " 'last_message': 'Preparing order',\n", + " 'last_modified': '2025-12-19T23:22:54.22275Z',\n", + " 'name': 'geometry_ref_order',\n", + " 'products': [{'item_ids': ['20220501_074035_74_2420'],\n", + " 'item_type': 'PSScene',\n", + " 'product_bundle': 'analytic_udm2'}],\n", + " 'state': 'queued',\n", + " 'tools': [{'clip': {'aoi': {'content': 'pl:features/my/cairo_areas-Kr7JYmq/1-owL5RyP',\n", + " 'type': 'ref'}}}]}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "order" + ] + }, + { + "cell_type": "markdown", + "id": "ef4fd626", + "metadata": {}, + "source": [ + "#### Downloading the completed Order\n", + "\n", + "Below is some code from the [planet_sdk_orders_demo](https://github.com/planetlabs/notebooks/blob/master/jupyter-notebooks/api_guides/orders_api/planet_sdk_orders_demo.ipynb) notebook that will allow you to download your order items after it has been completed. This is optional, and instead you can check out and download your order on [Planet Explorer](https://www.planet.com/explorer/) instead, where you will also find the [Features Manager](https://www.planet.com/features/). \n", + "\n", + "You now have all the tools you need to use the Features API with other Planet APIs!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b139ec3", + "metadata": {}, + "outputs": [], + "source": [ + "# You may need to wait a few minutes for the order to complete\n", + "order_id = order['id']\n", + "order = pl.orders.get_order(order_id)\n", + "print(f\"Your order request state is: {order['state']}\")\n", + "with reporting.StateBar() as bar:\n", + " pl.orders.wait(order_id, callback=bar.update_state)\n", + "\n", + "# if we get here that means the order completed. Yay! Download the files.\n", + "cwd = pathlib.Path.cwd()\n", + "output_dir = cwd / 'output'\n", + "if not pathlib.Path.exists(output_dir):\n", + " pathlib.Path.mkdir(output_dir)\n", + "output_paths = pl.orders.download_order(order_id, output_dir)\n", + "output_paths = [pathlib.Path.absolute(path) for path in output_paths]\n", + "output_paths" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv (3.13.7)", + "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.13.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}