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')
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 like STAC extensions fieldsto_h: -> Hash[String, untyped]
to_json: -> String
deep_dup: -> self
returns 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 valueself_href=: (String absolute_href) -> void
adds rel="self" link with the given hrefroot: -> Catalog?
returns rel="root" link as a catalog objectroot=: (Catalog? catalog) -> void
overwrites rel="root" linkparent: -> Catalog?
returns rel="parent" link as a catalog objectparent=: (Catalog? catalog) -> void
overwrites rel="parent" link
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.
STAC::Catalog
also has methods to crawl its links
:
children: -> Enumerator::Lazy[STAC::Catalog, void]
returns catalog/collection objects from rel="child" linkscollections: -> Enumerator::Lazy[STAC::Collection, void]
filters only collections from #childrenall_collections: -> Enumerator::Lazy[STAC::Collection, void]
returns all collections from the catalog and its children recursivelyitems: -> Enumerator::Lazy[STAC::Item, void]
returns item objects from rel="items" linksall_items: -> Enumerator::Lazy[STAC::Item, void]
returns all items from the catalog and its children recursivelyfind_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)
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
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
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 objectcollection=: (Collection collection) -> void
overwrites rel="collection" link and collection_id attribute
See STAC Item Specification for the details.
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_datetimedatetime_range=: (Range[Time]) -> void
sets #start_datetime and #end_datetime by the given rangelicense: -> 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"}
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
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.
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