Skip to main content
`Ctrl`+`K`

# PySTAC Introduction

This tutorial includes a basic introduction on reading, writing, and creating STAC objects using Pystac.

It is adapted from the tutorials within the sat-stac repo.

It uses an example stac stored in the `../example-catalog` directory along-side this notebook. The example stac has the following format:

    ../example-catalog
    ├── catalog.json
    └── landsat-8-l1
        ├── 2018-05
        │   └── LC80150322018141LGN00.json
        ├── 2018-06
        │   ├── LC80140332018166LGN00.json
        │   └── LC80300332018166LGN00.json
        ├── 2018-07
        │   └── LC80150332018189LGN00.json
        └── collection.json

    [1]:

    import pystac

## Working with existing catalogs

Open a root catalog from it’s json file

    [2]:

    cat = pystac.Catalog.from_file("../example-catalog/catalog.json")

We can see all elements of the STAC using the `describe` method

    [3]:

    cat.describe()

    * <Catalog id=landsat-stac-collection-catalog>
        * <Collection id=landsat-8-l1>
          * <Item id=LC80140332018166LGN00>
          * <Item id=LC80150322018141LGN00>
          * <Item id=LC80150332018189LGN00>
          * <Item id=LC80300332018166LGN00>

Each STAC object has links that you can use to traverse the STAC tree

    [4]:

    cat.links

    [4]:

    [<Link rel=self target=/home/jsignell/pystac/docs/example-catalog/catalog.json>,
     <Link rel=root target=<Catalog id=landsat-stac-collection-catalog>>,
     <Link rel=child target=<Collection id=landsat-8-l1>>]

Pystac has several methods that allow you to access links:

    [5]:

    # Get all child links
    cat.get_child_links()

    [5]:

    [<Link rel=child target=<Collection id=landsat-8-l1>>]

or the children directly:

    [6]:

    list(cat.get_children())

    [6]:

    [<Collection id=landsat-8-l1>]

    [7]:

    # or a single child by id
    cat.get_child("landsat-8-l1")

    [7]:

<Collection id=landsat-8-l1>

- type "Collection"
- id "landsat-8-l1"
- stac_version "1.1.0"
- description "Landsat 8 imagery radiometrically calibrated and orthorectified using ground points and Digital Elevation Model (DEM) data to correct relief displacement."
- links[] 7 items
  - 0
    - rel "root"
    - href "/home/jsignell/pystac/docs/example-catalog/catalog.json"
    - type "application/json"
    - title "STAC for Landsat data"
  - 1
    - rel "item"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/2018-06/LC80140332018166LGN00.json"
  - 2
    - rel "item"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/2018-05/LC80150322018141LGN00.json"
  - 3
    - rel "item"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/2018-07/LC80150332018189LGN00.json"
  - 4
    - rel "item"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/2018-06/LC80300332018166LGN00.json"
  - 5
    - rel "self"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/collection.json"
    - type "application/json"
  - 6
    - rel "parent"
    - href "/home/jsignell/pystac/docs/example-catalog/catalog.json"
    - type "application/json"
    - title "STAC for Landsat data"
- stac_extensions[] 1 items
  - 0 "https://example.com/stac/landsat-extension/1.0/schema.json"
- properties
  - collection "landsat-8-l1"
  - instruments[] 1 items
    - 0 "OLI_TIRS"
  - view:sun_azimuth 149.01607154
  - eo:bands[] 11 items
    - 0
      - name "B1"
      - full_width_half_max 0.02
      - center_wavelength 0.44
      - common_name "coastal"
    - 1
      - name "B2"
      - full_width_half_max 0.06
      - center_wavelength 0.48
      - common_name "blue"
    - 2
      - name "B3"
      - full_width_half_max 0.06
      - center_wavelength 0.56
      - common_name "green"
    - 3
      - name "B4"
      - full_width_half_max 0.04
      - center_wavelength 0.65
      - common_name "red"
    - 4
      - name "B5"
      - full_width_half_max 0.03
      - center_wavelength 0.86
      - common_name "nir"
    - 5
      - name "B6"
      - full_width_half_max 0.08
      - center_wavelength 1.6
      - common_name "swir16"
    - 6
      - name "B7"
      - full_width_half_max 0.22
      - center_wavelength 2.2
      - common_name "swir22"
    - 7
      - name "B8"
      - full_width_half_max 0.18
      - center_wavelength 0.59
      - common_name "pan"
    - 8
      - name "B9"
      - full_width_half_max 0.02
      - center_wavelength 1.37
      - common_name "cirrus"
    - 9
      - name "B10"
      - full_width_half_max 0.8
      - center_wavelength 10.9
      - common_name "lwir11"
    - 10
      - name "B11"
      - full_width_half_max 1
      - center_wavelength 12
      - common_name "lwir2"
  - view:off_nadir 0
  - view:azimuth 0
  - platform "landsat-8"
  - gsd 15
  - view:sun_elevation 59.214247
- title "Landsat 8 L1"
- extent
  - spatial
    - bbox[] 1 items
      - 0[] 4 items
        - 0 -180.0
        - 1 -90.0
        - 2 180.0
        - 3 90.0
  - temporal
    - interval[] 1 items
      - 0[] 2 items
        - 0 "2018-05-21T15:44:59Z"
        - 1 "2018-07-08T15:45:34Z"
- license "other"
- keywords[] 3 items
  - 0 "landsat"
  - 1 "earth observation"
  - 2 "usgs"
- providers[] 1 items
  - 0
    - name "Development Seed"
    - roles[] 1 items
      - 0 "processor"
    - url "https://github.com/sat-utils/sat-api"

    [8]:

    # Get a single link by 'rel'
    cat.get_single_link("self")

    [8]:

<Link rel=self target=/home/jsignell/pystac/docs/example-catalog/catalog.json>

- rel "self"
- href "/home/jsignell/pystac/docs/example-catalog/catalog.json"
- type "application/json"

    [9]:

    # Get item links directly within this catalog (there are none for this catalog)
    cat.get_item_links()

    [9]:

    []

or the items directly:

    [10]:

    # get item objects
    list(cat.get_items())

    [10]:

    []

    [11]:

    # get all items anywhere below this catalog on the STAC tree
    list(cat.get_items(recursive=True))

    [11]:

    [<Item id=LC80140332018166LGN00>,
     <Item id=LC80150322018141LGN00>,
     <Item id=LC80150332018189LGN00>,
     <Item id=LC80300332018166LGN00>]

You can access the stac item from a link using the `target` property

    [12]:

    link = cat.get_single_link("child")
    print(link)

    <Link rel=child target=<Collection id=landsat-8-l1>>

    [13]:

    print(link.target)

    <Collection id=landsat-8-l1>

You can convert any stac item to a python dict using the `to_dict` method.

    [14]:

    cat.to_dict(include_self_link=False)

    [14]:

    {'type': 'Catalog',
     'id': 'landsat-stac-collection-catalog',
     'stac_version': '1.1.0',
     'description': 'STAC for Landsat data',
     'links': [{'rel': 'root',
       'href': './catalog.json',
       'type': 'application/json',
       'title': 'STAC for Landsat data'},
      {'rel': 'child',
       'href': './landsat-8-l1/collection.json',
       'title': 'Landsat 8 L1'}],
     'title': 'STAC for Landsat data'}

    [15]:

    # get first (and only in this case) sub-catalog
    subcat = next(cat.get_children())

    [16]:

    # print some IDs
    print("Root Catalog: ", cat.id)
    print("Sub Catalog: ", subcat.id)
    print("Sub Catalog parent: ", subcat.get_parent().id)

    # iterate through child catalogs of the sub-catalog
    print("Sub Catalog children:")
    for child in subcat.get_children():
        print("    ", child.id)

    Root Catalog:  landsat-stac-collection-catalog
    Sub Catalog:  landsat-8-l1
    Sub Catalog parent:  landsat-stac-collection-catalog
    Sub Catalog children:

    [17]:

    print("\n**Items**")
    for i in cat.get_items(recursive=True):
        print(i.id)

    **Items**
    LC80140332018166LGN00
    LC80150322018141LGN00
    LC80150332018189LGN00
    LC80300332018166LGN00

## Creating new catalogs

You can initialize a new Catalog with an id and a description. Note that by default it sets a new catalog as root.

    [18]:

    # create a Catalog object with JSON
    mycat = pystac.Catalog(id="mycat", description="My shiny new STAC catalog")

    [19]:

    mycat.links

    [19]:

    [<Link rel=root target=<Catalog id=mycat>>]

## Adding catalogs to catalogs

    [20]:

    # add a new catalog to a root catalog
    kitten = pystac.Catalog(
        id="mykitten", description="A child catalog of my shiny new STAC catalog"
    )

When you add a child catalog to a parent catalog, the child catalog assumes the root catalog of it’s parent. ‘Child’ and ‘parent’ links are also added to the parent and child catalogs, respectively.

    [21]:

    kitten.links

    [21]:

    [<Link rel=root target=<Catalog id=mykitten>>]

    [22]:

    mycat.add_child(kitten)

    [22]:

<Link rel=child target=<Catalog id=mykitten>>

- rel "child"
- href None
- type "application/json"

    [23]:

    kitten.links

    [23]:

    [<Link rel=root target=<Catalog id=mycat>>,
     <Link rel=parent target=<Catalog id=mycat>>]

    [24]:

    mycat.links

    [24]:

    [<Link rel=root target=<Catalog id=mycat>>,
     <Link rel=child target=<Catalog id=mykitten>>]

    [25]:

    mycat.describe()

    * <Catalog id=mycat>
        * <Catalog id=mykitten>

## Adding collections to catalogs

In the next two steps we will work with Pystac Collections and Items. We will pull them out of our example catalog and add them to the new STAC that we have created.

Collections are Catalogs but also include spatial and temporal extents as well as additional properties.

    [26]:

    # open the Landsat collection
    collection = pystac.Collection.from_file(
        "../example-catalog/landsat-8-l1/collection.json"
    )
    collection

    [26]:

<Collection id=landsat-8-l1>

- type "Collection"
- id "landsat-8-l1"
- stac_version "1.1.0"
- description "Landsat 8 imagery radiometrically calibrated and orthorectified using ground points and Digital Elevation Model (DEM) data to correct relief displacement."
- links[] 7 items
  - 0
    - rel "self"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/collection.json"
    - type "application/json"
  - 1
    - rel "root"
    - href "../catalog.json"
  - 2
    - rel "parent"
    - href "../catalog.json"
  - 3
    - rel "item"
    - href "./2018-06/LC80140332018166LGN00.json"
  - 4
    - rel "item"
    - href "./2018-05/LC80150322018141LGN00.json"
  - 5
    - rel "item"
    - href "./2018-07/LC80150332018189LGN00.json"
  - 6
    - rel "item"
    - href "./2018-06/LC80300332018166LGN00.json"
- stac_extensions[] 1 items
  - 0 "https://example.com/stac/landsat-extension/1.0/schema.json"
- properties
  - collection "landsat-8-l1"
  - instruments[] 1 items
    - 0 "OLI_TIRS"
  - view:sun_azimuth 149.01607154
  - eo:bands[] 11 items
    - 0
      - name "B1"
      - full_width_half_max 0.02
      - center_wavelength 0.44
      - common_name "coastal"
    - 1
      - name "B2"
      - full_width_half_max 0.06
      - center_wavelength 0.48
      - common_name "blue"
    - 2
      - name "B3"
      - full_width_half_max 0.06
      - center_wavelength 0.56
      - common_name "green"
    - 3
      - name "B4"
      - full_width_half_max 0.04
      - center_wavelength 0.65
      - common_name "red"
    - 4
      - name "B5"
      - full_width_half_max 0.03
      - center_wavelength 0.86
      - common_name "nir"
    - 5
      - name "B6"
      - full_width_half_max 0.08
      - center_wavelength 1.6
      - common_name "swir16"
    - 6
      - name "B7"
      - full_width_half_max 0.22
      - center_wavelength 2.2
      - common_name "swir22"
    - 7
      - name "B8"
      - full_width_half_max 0.18
      - center_wavelength 0.59
      - common_name "pan"
    - 8
      - name "B9"
      - full_width_half_max 0.02
      - center_wavelength 1.37
      - common_name "cirrus"
    - 9
      - name "B10"
      - full_width_half_max 0.8
      - center_wavelength 10.9
      - common_name "lwir11"
    - 10
      - name "B11"
      - full_width_half_max 1
      - center_wavelength 12
      - common_name "lwir2"
  - view:off_nadir 0
  - view:azimuth 0
  - platform "landsat-8"
  - gsd 15
  - view:sun_elevation 59.214247
- title "Landsat 8 L1"
- extent
  - spatial
    - bbox[] 1 items
      - 0[] 4 items
        - 0 -180.0
        - 1 -90.0
        - 2 180.0
        - 3 90.0
  - temporal
    - interval[] 1 items
      - 0[] 2 items
        - 0 "2018-05-21T15:44:59Z"
        - 1 "2018-07-08T15:45:34Z"
- license "other"
- keywords[] 3 items
  - 0 "landsat"
  - 1 "earth observation"
  - 2 "usgs"
- providers[] 1 items
  - 0
    - name "Development Seed"
    - roles[] 1 items
      - 0 "processor"
    - url "https://github.com/sat-utils/sat-api"

See the spatial and temporal extent of this collection

    [27]:

    collection.extent.to_dict()

    [27]:

    {'spatial': {'bbox': [[-180.0, -90.0, 180.0, 90.0]]},
     'temporal': {'interval': [['2018-05-21T15:44:59Z', '2018-07-08T15:45:34Z']]}}

    [28]:

    collection.links

    [28]:

    [<Link rel=self target=/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/collection.json>,
     <Link rel=root target=../catalog.json>,
     <Link rel=parent target=../catalog.json>,
     <Link rel=item target=./2018-06/LC80140332018166LGN00.json>,
     <Link rel=item target=./2018-05/LC80150322018141LGN00.json>,
     <Link rel=item target=./2018-07/LC80150332018189LGN00.json>,
     <Link rel=item target=./2018-06/LC80300332018166LGN00.json>]

    [29]:

    # add it to the child catalog created above
    kitten.add_child(collection)

    [29]:

<Link rel=child target=<Collection id=landsat-8-l1>>

- rel "child"
- href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/collection.json"
- type "application/json"
- title "Landsat 8 L1"

    [30]:

    collection.links

    [30]:

    [<Link rel=self target=/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/collection.json>,
     <Link rel=root target=<Catalog id=mycat>>,
     <Link rel=item target=./2018-06/LC80140332018166LGN00.json>,
     <Link rel=item target=./2018-05/LC80150322018141LGN00.json>,
     <Link rel=item target=./2018-07/LC80150332018189LGN00.json>,
     <Link rel=item target=./2018-06/LC80300332018166LGN00.json>,
     <Link rel=parent target=<Catalog id=mykitten>>]

## Adding items to collection

Items are stac objects whose parents can be either Catalogs or Collections. They also have spatio-temporal information and assets. Assets point directly to the data included in the STAC.

    [31]:

    # open a Landsat item
    item = pystac.read_file(
        "../example-catalog/landsat-8-l1/2018-05/LC80150322018141LGN00.json"
    )
    item

    [31]:

<Item id=LC80150322018141LGN00>

- type "Feature"
- stac_version "1.1.0"
- stac_extensions[] 3 items
  - 0 "https://stac-extensions.github.io/eo/v1.1.0/schema.json"
  - 1 "https://stac-extensions.github.io/view/v1.0.0/schema.json"
  - 2 "https://stac-extensions.github.io/projection/v2.0.0/schema.json"
- id "LC80150322018141LGN00"
- geometry
  - type "Polygon"
  - coordinates[] 1 items
    - 0[] 5 items
      - 0[] 2 items
        - 0 -77.28911976020206
        - 1 41.40912394323429
      - 1[] 2 items
        - 0 -75.07576783500748
        - 1 40.97162247589133
      - 2[] 2 items
        - 0 -75.66872631473827
        - 1 39.23210949585851
      - 3[] 2 items
        - 0 -77.87946700654118
        - 1 39.67679918442899
      - 4[] 2 items
        - 0 -77.28911976020206
        - 1 41.40912394323429
- bbox[] 4 items
  - 0 -77.88298
  - 1 39.23073
  - 2 -75.07535
  - 3 41.41022
- properties
  - collection "landsat-8-l1"
  - datetime "2018-05-21T15:44:59Z"
  - view:sun_azimuth 134.8082647
  - view:sun_elevation 64.00406717
  - eo:cloud_cover 4
  - instruments[] 1 items
    - 0 "OLI_TIRS"
  - view:off_nadir 0
  - platform "landsat-8"
  - gsd 30
  - proj:transform[] 6 items
    - 0 258885.0
    - 1 30.0
    - 2 0.0
    - 3 4584315.0
    - 4 0.0
    - 5 -30.0
  - proj:geometry
    - type "Polygon"
    - coordinates[] 1 items
      - 0[] 5 items
        - 0[] 2 items
          - 0 258885.0
          - 1 4346085.0
        - 1[] 2 items
          - 0 258885.0
          - 1 4584315.0
        - 2[] 2 items
          - 0 493515.0
          - 1 4584315.0
        - 3[] 2 items
          - 0 493515.0
          - 1 4346085.0
        - 4[] 2 items
          - 0 258885.0
          - 1 4346085.0
  - proj:shape[] 2 items
    - 0 7821
    - 1 7941
  - proj:code "EPSG:32618"
- links[] 4 items
  - 0
    - rel "self"
    - href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/2018-05/LC80150322018141LGN00.json"
    - type "application/json"
  - 1
    - rel "parent"
    - href "../collection.json"
  - 2
    - rel "collection"
    - href "../collection.json"
  - 3
    - rel "root"
    - href "../../catalog.json"
- assets
  - index
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/index.html"
    - type "text/html"
    - title "HTML index page"
    - roles[] 0 items
  - thumbnail
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_thumb_large.jpg"
    - type "image/jpeg"
    - title "Thumbnail image"
    - roles[] 1 items
      - 0 "thumbnail"
  - B1
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B1.TIF"
    - type "image/tiff"
    - title "Band 1 (coastal)"
    - eo:bands[] 1 items
      - 0
        - name "B1"
        - full_width_half_max 0.02
        - center_wavelength 0.44
        - common_name "coastal"
    - roles[] 0 items
  - B2
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B2.TIF"
    - type "image/tiff"
    - title "Band 2 (blue)"
    - eo:bands[] 1 items
      - 0
        - name "B2"
        - full_width_half_max 0.06
        - center_wavelength 0.48
        - common_name "blue"
    - roles[] 0 items
  - B3
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B3.TIF"
    - type "image/tiff"
    - title "Band 3 (green)"
    - eo:bands[] 1 items
      - 0
        - name "B3"
        - full_width_half_max 0.06
        - center_wavelength 0.56
        - common_name "green"
    - roles[] 0 items
  - B4
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B4.TIF"
    - type "image/tiff"
    - title "Band 4 (red)"
    - eo:bands[] 1 items
      - 0
        - name "B4"
        - full_width_half_max 0.04
        - center_wavelength 0.65
        - common_name "red"
    - roles[] 0 items
  - B5
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B5.TIF"
    - type "image/tiff"
    - title "Band 5 (nir)"
    - eo:bands[] 1 items
      - 0
        - name "B5"
        - full_width_half_max 0.03
        - center_wavelength 0.86
        - common_name "nir"
    - roles[] 0 items
  - B6
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B6.TIF"
    - type "image/tiff"
    - title "Band 6 (swir16)"
    - eo:bands[] 1 items
      - 0
        - name "B6"
        - full_width_half_max 0.08
        - center_wavelength 1.6
        - common_name "swir16"
    - roles[] 0 items
  - B7
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B7.TIF"
    - type "image/tiff"
    - title "Band 7 (swir22)"
    - eo:bands[] 1 items
      - 0
        - name "B7"
        - full_width_half_max 0.22
        - center_wavelength 2.2
        - common_name "swir22"
    - roles[] 0 items
  - B8
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B8.TIF"
    - type "image/tiff"
    - title "Band 8 (pan)"
    - eo:bands[] 1 items
      - 0
        - name "B8"
        - full_width_half_max 0.18
        - center_wavelength 0.59
        - common_name "pan"
    - roles[] 0 items
  - B9
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B9.TIF"
    - type "image/tiff"
    - title "Band 9 (cirrus)"
    - eo:bands[] 1 items
      - 0
        - name "B9"
        - full_width_half_max 0.02
        - center_wavelength 1.37
        - common_name "cirrus"
    - roles[] 0 items
  - B10
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B10.TIF"
    - type "image/tiff"
    - title "Band 10 (lwir)"
    - eo:bands[] 1 items
      - 0
        - name "B10"
        - full_width_half_max 0.8
        - center_wavelength 10.9
        - common_name "lwir11"
    - roles[] 0 items
  - B11
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B11.TIF"
    - type "image/tiff"
    - title "Band 11 (lwir)"
    - eo:bands[] 1 items
      - 0
        - name "B11"
        - full_width_half_max 1
        - center_wavelength 12
        - common_name "lwir2"
    - roles[] 0 items
  - ANG
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_ANG.txt"
    - type "text/plain"
    - title "Angle coefficients file"
    - roles[] 0 items
  - MTL
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_MTL.txt"
    - type "text/plain"
    - title "original metadata file"
    - roles[] 0 items
  - BQA
    - href "https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_BQA.TIF"
    - type "image/tiff"
    - title "Band quality data"
    - roles[] 0 items
- collection "landsat-8-l1"

    [32]:

    item.links

    [32]:

    [<Link rel=self target=/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/2018-05/LC80150322018141LGN00.json>,
     <Link rel=parent target=../collection.json>,
     <Link rel=collection target=../collection.json>,
     <Link rel=root target=../../catalog.json>]

    [33]:

    item.assets

    [33]:

    {'index': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/index.html>,
     'thumbnail': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_thumb_large.jpg>,
     'B1': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B1.TIF>,
     'B2': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B2.TIF>,
     'B3': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B3.TIF>,
     'B4': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B4.TIF>,
     'B5': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B5.TIF>,
     'B6': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B6.TIF>,
     'B7': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B7.TIF>,
     'B8': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B8.TIF>,
     'B9': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B9.TIF>,
     'B10': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B10.TIF>,
     'B11': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_B11.TIF>,
     'ANG': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_ANG.txt>,
     'MTL': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_MTL.txt>,
     'BQA': <Asset href=https://s3-us-west-2.amazonaws.com/landsat-pds/c1/L8/015/032/LC08_L1TP_015032_20180521_20180605_01_T1/LC08_L1TP_015032_20180521_20180605_01_T1_BQA.TIF>}

    [34]:

    # add it to the collection created above
    collection.add_item(item)

    [34]:

<Link rel=item target=<Item id=LC80150322018141LGN00>>

- rel "item"
- href "/home/jsignell/pystac/docs/example-catalog/landsat-8-l1/LC80150322018141LGN00/LC80150322018141LGN00.json"
- type "application/geo+json"

    [35]:

    # now look at the catalog we've created
    mycat.describe()

    * <Catalog id=mycat>
        * <Catalog id=mykitten>
            * <Collection id=landsat-8-l1>
              * <Item id=LC80140332018166LGN00>
              * <Item id=LC80150322018141LGN00>
              * <Item id=LC80150332018189LGN00>
              * <Item id=LC80300332018166LGN00>
              * <Item id=LC80150322018141LGN00>

Currently, this STAC only exists in memory. We can use `normalize_and_save` to save off the STAC with the canonical “absolute published” form:

    [36]:

    mycat.normalize_and_save(
        "pystac-example-absolute", catalog_type=pystac.CatalogType.ABSOLUTE_PUBLISHED
    )

Notice now that the ‘parent’ link of an item is a absolute HREF:

    [37]:

    item = next(mycat.get_items(recursive=True))
    item.get_single_link("parent").get_href()

    [37]:

    '/home/jsignell/pystac/docs/tutorials/pystac-example-absolute/mykitten/landsat-8-l1/collection.json'

We can also normalize and save the catalog to the other types described in the best practices documentation: “relative published” and “self contained”. A self contained catalog contains all relative links, and no self links. Notice how saving a self contained catalog will produce relative links:

    [38]:

    mycat.normalize_and_save(
        "pystac-example-relative", catalog_type=pystac.CatalogType.SELF_CONTAINED
    )

    [39]:

    item = next(mycat.get_items(recursive=True))
    item.get_single_link("parent").get_href()

    [39]:

    '../collection.json'