Getting Started¶ ↑
Reading STAC Objects¶ ↑
You can read any STAC objects from URL by STAC.from_url:
catalog = STAC.from_url('https://raw.githubusercontent.com/radiantearth/stac-spec/master/examples/catalog.json') catalog.class #=> STAC::Catalog catalog.type #=> "Catalog" collection = STAC.from_url('https://raw.githubusercontent.com/radiantearth/stac-spec/master/examples/collection.json') collection.class #=> STAC::Collection collection.type #=> "Collection" item = STAC.from_item('https://raw.githubusercontent.com/radiantearth/stac-spec/master/examples/core-item.json') item.class #=> STAC::Item item.type #=> "Feature"
Also, from a local file by STAC.from_file:
catalog = STAC.from_file('/path/to/local/catalog.json') collection = STAC.from_file('/path/to/local/collection.json') item = STAC.from_file('/path/to/local/item.json')
STAC Object Classes¶ ↑
There are 3 core STAC object classes: STAC::Catalog, STAC::Collection, and STAC::Item.
They have a class method from_hash(hash), which returns its instance converted from the given Hash.
catalog = STAC::Catalog.from_hash( { 'stac_version' => '1.0.0', 'type' => 'Catalog', 'id' => '20201211_223832_CS2', 'description' => 'A simple catalog example', 'links' => [], } )
And they have the following instance methods in common:
-
extra: -> Hash[String, untyped]returns extra fields that do not belong to the core specification likeSTACextensions fields -
to_h: -> Hash[String, untyped] -
to_json: -> String -
deep_dup: -> selfreturns a deep copy of self. -
stac_extensions: -> Array[String] -
add_extension: (String extension_id) -> self | (Module extension) -> self(see Extensions) -
links: -> Array[STAC::Link] -
find_link: (rel: String, ?type: String?) -> STAC::Link? -
add_link: (rel: String, href: String, ?type: String?, ?title: String?) -> self
Followings are shorthand methods for core links:
-
self_href: -> String?returns rel=“self” link’s href value -
self_href=: (String absolute_href) -> voidadds rel=“self” link with the given href -
root: -> Catalog?returns rel=“root” link as a catalog object -
root=: (Catalog? catalog) -> voidoverwrites rel=“root” link -
parent: -> Catalog?returns rel=“parent” link as a catalog object -
parent=: (Catalog? catalog) -> voidoverwrites rel=“parent” link
STAC::Catalog¶ ↑
STAC::Catalog has the following attributes:
-
attr_accessor id: String -
attr_accessor description: String -
attr_accessor title: String?
catalog.id = 'awesome_catalog' catalog.id #=> "awesome_catalog"
See STAC Catalog Specification for the details.
Crawling Catalog Links¶ ↑
STAC::Catalog also has methods to crawl its links:
-
children: -> Enumerator::Lazy[STAC::Catalog, void]returns catalog/collection objects from rel=“child” links -
collections: -> Enumerator::Lazy[STAC::Collection, void]filters only collections from children -
all_collections: -> Enumerator::Lazy[STAC::Collection, void]returns all collections from the catalog and its children recursively -
items: -> Enumerator::Lazy[STAC::Item, void]returns item objects from rel=“items” links -
all_items: -> Enumerator::Lazy[STAC::Item, void]returns all items from the catalog and its children recursively -
find_child: (String id, ?recursive: bool) -> STAC::Catalog? -
find_item: (String id, ?recursive: bool) -> STAC::Item?
Note that the first 5 methods return {Enumerator::Lazy}. This is to prevent making a large number of HTTP requests when calling the methods.
catalog.collections.each do |collection| puts collection.id end collection = catalog.find_child('awesome_collection') catalog.all_items.first(100).each do |item| puts item.id end item = catalog.find_item('awesome_item', recursive: true)
Exporting Catalog¶ ↑
Furthermore, STAC::Catalog has methods to create a new static STAC catalog:
-
add_child: (Catalog catalog, ?href: String, ?title: String?) -> self -
add_item: (Item item, ?href: String, ?title: String?) -> self -
export: (?String? dest_dir) -> void
catalog = STAC::Catalog.new(id: 'root', description: 'The root catalog') catalog.self_href = 'https://example.com/catalog.json' catalog.root = catalog item = STAC::Item.from_hash( { 'stac_version' => '1.0.0', 'type' => 'Feature', 'id' => 'item', 'geometry' => nil, 'properties' => { 'datetime' => Time.now.iso8601 }, 'links' => [], 'assets' => {} } ) # Add rel="item" link to catalog with href="#{item.id}.json" (based on best practice). # And add rel="self", rel="root", and rel="parent" links to item. catalog.add_item(item) item.links.each { |l| puts "#{l.rel}: #{l.href}" } # self: https://example.com/item.json # root: https://example.com/catalog.json # parent: https://example.com/catalog.json sub_catalog = STAC::Catalog.new(id: 'sub-catalog', description: 'The sub catalog') # Add rel="child" link to catalog with href="#{catalog.id}/catalog.json". # Also add rel="self", rel="root", and rel="parent" links to sub-catalog. catalog.add_child(sub_catalog) sub_catalog.add_item(item.deep_dup.update(id: 'sub-item')) sub_catalog.links.each { |l| puts "#{l.rel}: #{l.href}" } # self: https://example.com/sub-catalog/catalog.json # root: https://example.com/catalog.json # parent: https://example.com/catalog.json # item: https://example.com/sub-catalog/sub-item.json catalog.links.each { |l| puts "#{l.rel}: #{l.href}" } # self: https://example.com/catalog.json # root: https://example.com/catalog.json # item: https://example.com/item.json # child: https://example.com/sub-catalog/catalog.json # Exports the catalog and its children/item recursively to the given directory. catalog.export('path/to/dest') # $ tree path/to/dest # path/to/dest # ├── catalog.json # ├── item.json # └── sub-catalog # ├── catalog.json # └── sub-item.json
STAC::Collection¶ ↑
STAC::Collection inherits STAC::Catalog.
The followings are STAC::Collection specific attributes:
-
attr_accessor license: String -
attr_accessor extent: STAC::Extent -
attr_accessor keywords: Array[String]? -
attr_accessor providers: Array[STAC::Provider]? -
attr_accessor summaries: Hash[String, untyped]? -
attr_reader assets: Hash[String, STAC::Asset]?
To add an asset, use:
-
add_asset: (key: String, href: String, ?title: String?, ?description: String?, ?type: String?, ?roles: Array[String]?) -> self
STAC::Extent, STAC::Provider, and STAC::Asset provide accessors for the corresponding object’s fields.
collection.extent.spatial.bbox = [-180, -90, 180, 90] collection.extent.spatial.bbox #=> [-180, -90, 180, 90] collection.extent.temporal.interval = ['2022-12-01T00:00:00Z', null] collection.extent.temporal.interval #=> ["2022-12-01T00:00:00Z", null] collection.providers << STAC::Provider.new(name: 'sankichi92') collection.providers.last.name #=> "sankichi92"
See STAC Collection Specification for the details.
STAC::Item¶ ↑
STAC::Item has the following attributes:
-
attr_accessor id: String -
attr_reader properties: STAC::Properties -
attr_reader assets: Hash[String, STAC::Asset] -
attr_accessor geometry: Hash[String, untyped]? -
attr_accessor bbox: Array[Numeric]? -
attr_accessor collection_id: String?
And has the following methods:
-
add_asset: (key: String, href: String, ?title: String?, ?description: String?, ?type: String?, ?roles: Array[String]?) -> self -
collection: -> Collection?returns a rel=“collection” link as a collection object -
collection=: (Collection collection) -> voidoverwrites rel=“collection” link and collection_id attribute
See STAC Item Specification for the details.
Common Metadata¶ ↑
STAC::Properties and STAC::Asset includes STAC::CommonMetadata, which provides read/write methods for STAC Common Metadata fields:
-
title: -> String? -
title=: (String) -> void -
description: -> String? -
description=: (String) -> void -
created: -> Time? -
created=: (Time | String) -> void -
updated: -> Time? -
updated=: (Time | String) -> void -
start_datetime: -> Time? -
start_datetime=: (Time | String) -> void -
end_datetime: -> Time? -
end_datetime=: (Time | String) -> void -
datetime_range: -> Range[Time]?returns a range from start_datetime to end_datetime -
datetime_range=: (Range[Time]) -> voidsets start_datetime and end_datetime by the given range -
license: -> String? -
license=: (String) -> void -
providers: -> Array[Provider] -
providers=: (Array[Provider | Hash[String, untyped]]) -> void -
platform: -> String? -
platform=: (String) -> void -
instruments: -> Array[String]? -
instruments=: (Array[String]) -> void -
constellation: -> String? -
constellation=: (String) -> void -
mission: -> String? -
mission=: (String) -> void -
gsd: -> Numeric -
gsd=: (Numeric) -> void
These methods are shorthand accessors of #extra hash:
item.properties.extra #=> {} item.properties.title = 'Awesome Item' # same as `item.properties.extra['title'] = 'Awesome Item'` item.properties.title #=> "Awesome Item" item.properties.extra #=> {"title"=>"Awesome Item"}
Extensions¶ ↑
When an extension is added to a STAC object, methods corresponding to the extension will be added dynamically by {Object#extend}.
These methods are also shorthand accessors of extra hash same as STAC::CommonMetadata.
item.stac_extensions #=> [] item.properties.extra #=> {} item.properties.eo_cloud_cover #=> raises NoMethodError item.add_extension('https://stac-extensions.github.io/eo/v1.0.0/schema.json') # same as `item.add_extension(STAC::Extensions::ElectroOptical)` item.stac_extensions #=> ["https://stac-extensions.github.io/eo/v1.0.0/schema.json"] item.properties.eo_cloud_cover = 1.2 item.properties.eo_cloud_cover #=> 1.2 item.properties.extra #=> {"eo:cloud_cover"=>1.2} # item.properties extends STAC::Extensions::ElectroOptical::Properties item.properties.is_a?(STAC::Extensions::ElectroOptical::Properties) #=> true
Currently, only 4 stable extensions have been implemented:
puts STAC::STACObject.extendables # STAC::Extensions::ElectroOptical # STAC::Extensions::Projection # STAC::Extensions::ScientificCitation # STAC::Extensions::ViewGeometry
Adding Extensions¶ ↑
You can add custom extensions.
Extension modules must extend STAC::Extension and set identifier and scope. And you must register it by STAC::STACObject.add_extendable(extension_module).
module MyExtension extend STAC::Extension identifier 'https://sankichi92.github.io/my_extension/v1.0.0/schema.json' scope STAC::Item, STAC::Collection end STAC::STACObject.add_extendable(MyExtension)
Then you can add methods to STAC::Properties, STAC::Asset, and STAC::Collection by defining modules with corresponding names under the extension namespace:
module MyExtension module Properties def my_field extra['my:field'] end def my_field(val) extra['my:field'] = val end end module Asset include Properties end end
See {lib/stac/extensions} for examples.
Using Custom HTTP Client¶ ↑
Custom HTTP client class must implement get: (URI | String url) -> Hash[String, untyped], which returns response JSON as a Hash:
class MyHTTPClient def get(url) # ... end end
You can pass the custom HTTP client to STAC.from_url for a specific STAC object instance:
catalog = STAC.from_url('https://example.com/catalog.json', http_client: MyHTTPClient.new)
Or you can set it as the global default by STAC.default_http_client=:
STAC.default_http_client = MyHTTPClient.new
If you want to only add custom HTTP headers, you can use STAC::SimpleHTTPClient:
http_client = STAC::SimpleHTTPClient.new({ 'X-Foo' => 'Bar' }) catalog = STAC.from_url('https://example.com/catalog.json', http_client:) STAC.default_http_client = http_client