StacProduct#

class StacProduct(product_path: str | CloudPath | Path, archive_path: str | CloudPath | Path | None = None, output_path: str | CloudPath | Path | None = None, remove_tmp: bool = False, **kwargs)[source]#

Bases: Product

Stac products

__init__(product_path: str | CloudPath | Path, archive_path: str | CloudPath | Path | None = None, output_path: str | CloudPath | Path | None = None, remove_tmp: bool = False, **kwargs) None#
clean_tmp()#

Clean the temporary directory of the current product

clear()#

Clear this product’s cache

abstract get_band_paths(band_list: list, pixel_size: float | None = None, **kwargs) dict#

Return the paths of required bands.

>>> from eoreader.reader import Reader
>>> from eoreader.bands import *
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_band_paths([GREEN, RED])
{
    <SpectralBandNames.GREEN: 'GREEN'>: 'zip+file://S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip!/S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE/GRANULE/L1C_T30TTK_A027018_20200824T111345/IMG_DATA/T30TTK_20200824T110631_B03.jp2',
    <SpectralBandNames.RED: 'RED'>: 'zip+file://S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip!/S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE/GRANULE/L1C_T30TTK_A027018_20200824T111345/IMG_DATA/T30TTK_20200824T110631_B04.jp2'
}
Parameters:
  • band_list (list) – List of the wanted bands

  • pixel_size (float) – Band pixel size (in meters)

  • kwargs – Other arguments used to load bands

Returns:

Dictionary containing the path of each queried band

Return type:

dict

get_date(as_date: bool = False) str | date#

Get the product’s acquisition date.

>>> from eoreader.reader import Reader
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_date(as_date=True)
datetime.datetime(2020, 8, 24, 0, 0)
>>> prod.get_date(as_date=False)
'20200824'
Parameters:

as_date (bool) – Return the date as a datetime.date. If false, returns a string.

Returns:

Its acquisition date

Return type:

str

abstract get_datetime(as_datetime: bool = False) str | datetime#

Get the product’s acquisition datetime, with format YYYYMMDDTHHMMSS <-> %Y%m%dT%H%M%S

>>> from eoreader.reader import Reader
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_datetime(as_datetime=True)
datetime.datetime(2020, 8, 24, 11, 6, 31)
>>> prod.get_datetime(as_datetime=False)
'20200824T110631'
Parameters:

as_datetime (bool) – Return the date as a datetime.datetime. If false, returns a string.

Returns:

Its acquisition datetime

Return type:

Union[str, datetime]

abstract get_default_band() BandNames#

Get default band: Usually GREEN band for optical data and the first existing one between VV and HH for SAR data.

>>> from eoreader.reader import Reader
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_default_band()
<SpectralBandNames.GREEN: 'GREEN'>
Returns:

Default band

Return type:

str

abstract get_default_band_path(**kwargs) CloudPath | Path#

Get default band path (among the existing ones).

Usually GREEN band for optical data and the first existing one between VV and HH for SAR data.

>>> from eoreader.reader import Reader
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_default_band_path()
'zip+file://S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip!/S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE/GRANULE/L1C_T30TTK_A027018_20200824T111345/IMG_DATA/T30TTK_20200824T110631_B03.jp2'
Parameters:

kwargs – Additional arguments

Returns:

Default band path

Return type:

AnyPathType

get_e84_client()[source]#

Get Element-84 client (for stac-asset)

abstract get_existing_band_paths() dict#

Return the existing band paths (orthorectified if needed).

>>> from eoreader.reader import Reader
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_existing_band_paths()
{
    <SpectralBandNames.CA: 'COASTAL_AEROSOL'>: 'zip+file://S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip!/S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE/GRANULE/L1C_T30TTK_A027018_20200824T111345/IMG_DATA/T30TTK_20200824T110631_B01.jp2',
    ...,
    <SpectralBandNames.SWIR_2: 'SWIR_2'>: 'zip+file://S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip!/S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE/GRANULE/L1C_T30TTK_A027018_20200824T111345/IMG_DATA/T30TTK_20200824T110631_B12.jp2'
}
Returns:

Dictionary containing the path of each queried band

Return type:

dict

abstract get_existing_bands() list#

Return the existing bands.

>>> from eoreader.reader import Reader
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.get_existing_bands()
[<SpectralBandNames.CA: 'COASTAL_AEROSOL'>,
<SpectralBandNames.BLUE: 'BLUE'>,
<SpectralBandNames.GREEN: 'GREEN'>,
<SpectralBandNames.RED: 'RED'>,
<SpectralBandNames.VRE_1: 'VEGETATION_RED_EDGE_1'>,
<SpectralBandNames.VRE_2: 'VEGETATION_RED_EDGE_2'>,
<SpectralBandNames.VRE_3: 'VEGETATION_RED_EDGE_3'>,
<SpectralBandNames.NIR: 'NIR'>,
<SpectralBandNames.NNIR: 'NARROW_NIR'>,
<SpectralBandNames.WV: 'WATER_VAPOUR'>,
<SpectralBandNames.CIRRUS: 'CIRRUS'>,
<SpectralBandNames.SWIR_1: 'SWIR_1'>,
<SpectralBandNames.SWIR_2: 'SWIR_2'>]
Returns:

List of existing bands in the products

Return type:

list

get_quicklook_path() None | str#

Get quicklook path if existing (no such thing for Sentinel-2)

Returns:

Quicklook path

Return type:

str

get_raw_band_paths(**kwargs) dict#

Return the raw band paths.

Parameters:

kwargs – Additional arguments

Returns:

Dictionary containing the path of each queried band

Return type:

dict

get_s3_client(region_name: str, requester_pays: bool = False, **kwargs)[source]#

Get a Client (for stac-asset) :param region_name: Region name :type region_name: str :param requester_pays: Requester pays :type requester_pays: bool :param **kwargs: Other args

Returns:

get_sinergise_client()[source]#

Get Sinergise S3 client (for stac-asset)

get_usgs_client()[source]#

Get USGS Landsat client (for stac-asset)

has_band(band: BandNames | str) bool#

Does this product has the specified band ?

By band, we mean:

  • satellite band

  • index

  • DEM band

  • cloud band

>>> from eoreader.reader import Reader
>>> from eoreader.bands import *
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> prod.has_band(GREEN)
True
>>> prod.has_band(TIR_2)
False
>>> prod.has_band(NDVI)
True
>>> prod.has_band(SHADOWS)
False
>>> prod.has_band(HILLSHADE)
True
Parameters:

band (Union[BandNames, str]) – EOReader band (optical, SAR, clouds, DEM)

Returns:

True if the products has the specified band

Return type:

bool

has_bands(bands: list | BandNames | str) bool#

Does this product has the specified bands ?

By band, we mean:

  • satellite band

  • index

  • DEM band

  • cloud band

See has_band for a code example.

Parameters:

bands (Union[list, BandNames, str]) – EOReader bands (optical, SAR, clouds, DEM)

Returns:

True if the products has the specified band

Return type:

bool

load(bands: list | BandNames | str, pixel_size: float | None = None, size: list | tuple | None = None, **kwargs) Dataset#

Open the bands and compute the wanted index.

  • For Optical data:

    The bands will be purged of nodata and invalid pixels (if specified with the CLEAN_OPTICAL keyword), the nodata will be set to -9999 and the bands will be DataArrays in float32.

  • For SAR data:

    The bands will be purged of nodata (not over the sea), the nodata will be set to 0 to respect SNAP’s behavior and the bands will be DataArray in float32.

Bands that come out this function at the same time are collocated and therefore have the same shapes. This can be broken if you load data separately. Its is best to always load DEM data with some real bands.

>>> from eoreader.reader import Reader
>>> from eoreader.bands import *
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> bands = prod.load([GREEN, NDVI], pixel_size=20)
Parameters:
  • bands (Union[list, BandNames, str]) – Band list

  • pixel_size (float) – Pixel size of the band, in meters

  • size (Union[tuple, list]) – Size of the array (width, height). Not used if pixel_size is provided.

  • kwargs – Other arguments used to load bands

Returns:

Dataset with a variable per band

Return type:

xr.Dataset

plot() None[source]#

Plot the quicklook if existing

read_href(href: str, config=None, clients=None) bytes[source]#

Read HREF (with stac-asset.blocking)

Parameters:
  • href – The href to read

  • config – The download configuration to use

  • clients – Any pre-configured clients to use

Returns:

The bytes from the href

Return type:

bytes

read_mtd()#

Read metadata and outputs the metadata XML root and its namespaces as a dict.

>>> from eoreader.reader import Reader
>>> path = r"S1A_IW_GRDH_1SDV_20191215T060906_20191215T060931_030355_0378F7_3696.zip"
>>> prod = Reader().open(path)
>>> prod.read_mtd()
(<Element product at 0x1832895d788>, '')
Returns:

Metadata XML root and its namespace

Return type:

(etree._Element, dict)

sign_url(url: str) str[source]#

Sign URL with planetary computer if installed. :param url: URL to sign :type url: str

Returns:

Signed URL

Return type:

str

stack(bands: list, pixel_size: float | None = None, size: list | tuple | None = None, stack_path: str | CloudPath | Path | None = None, save_as_int: bool = False, **kwargs) DataArray#

Stack bands and index of a products.

>>> from eoreader.reader import Reader
>>> from eoreader.bands import *
>>> path = r"S2A_MSIL1C_20200824T110631_N0209_R137_T30TTK_20200824T150432.SAFE.zip"
>>> prod = Reader().open(path)
>>> stack = prod.stack([NDVI, MNDWI, GREEN], pixel_size=20)  # In meters
Parameters:
  • bands (list) – Bands and index combination

  • pixel_size (float) – Stack pixel size. . If not specified, use the product pixel size.

  • size (Union[tuple, list]) – Size of the array (width, height). Not used if pixel_size is provided.

  • stack_path (AnyPathStrType) – Stack path

  • save_as_int (bool) – Convert stack to uint16 to save disk space (and therefore multiply the values by 10.000)

  • **kwargs – Other arguments passed to load or rioxarray.to_raster() (such as compress)

Returns:

Stack as a DataArray

Return type:

xr.DataArray

to_band(raw_bands: list | BandNames | str | int) list#

Convert any raw band identifier to a usable band.

Bands can be called with their name, ID or mapped name. For example, for Sentinel-3 OLCI you can use 7, Oa07 or YELLOW. For Landsat-8, you can use BLUE or 2.

Parameters:

raw_bands (Union[list, BandNames, str, int]) – Raw bands

Returns:

Mapped bands

Return type:

list

archive_path#

Archive path, same as the product path if not specified. Useful when you want to know where both the extracted and archived version of your product are stored.

bands#

Band mapping between band wrapping names such as GREEN and band real number such as 03 for Sentinel-2.

clients = None#
condensed_name#

Condensed name, the filename with only useful data to keep the name unique (ie. 20191215T110441_S2_30TXP_L2A_122756). Used to shorten names and paths.

constellation#

Product constellation, such as Sentinel-2

constellation_id#

Constellation ID, i.e. S2 for Sentinel-2

corresponding_ref#

The corresponding reference products to the current one (if the product is not a reference but has a reference data corresponding to it). A list because of multiple ref in case of non-stackable products (S3, S1…)

crs = <methodtools._LruCacheWire object>[source]#
date#

Acquisition date.

datetime#

Acquisition datetime.

default_clients = None#
default_transform = <methodtools._LruCacheWire object>#
extent = <methodtools._LruCacheWire object>[source]#
filename#

Product filename

footprint = <methodtools._LruCacheWire object>[source]#
get_orbit_direction = <methodtools._LruCacheWire object>#
instrument#

Product instrument, such as MSI for Sentinel-2 data.

is_archived#

Is the archived product is processed (a products is considered as archived if its products path is a directory).

is_ortho#

True if the images are orthorectified and the footprint is retrieved easily.

is_reference#

If the product is a reference, used for algorithms that need pre and post data, such as fire detection.

is_stacked#

True if the bands are stacked (like for VHR data).

item = None#
name#

Product true name (as specified in the metadata)

needs_extraction#

Does this product needs to be extracted to be processed ? (True by default).

nodata#

Product nodata, set to -9999 by default

property output: CloudPath | Path#

Output directory of the product, to write orthorectified data for example.

path#

Usable path to the product, either extracted or archived path, according to the satellite.

pixel_size#

For SAR data, it is important to distinguish (square) pixel spacing from actual resolution. (see this <https://natural-resources.canada.ca/maps-tools-and-publications/satellite-imagery-and-air-photos/tutorial-fundamentals-remote-sensing/satellites-and-sensors/spatial-resolution-pixel-size-and-scale/9407> for more information). For optical data, those two terms have usually the same meaning (for a fully zoomed raster).

product_type#

Product type, satellite-related field, such as L1C or L2A for Sentinel-2 data.

resolution#

Default resolution in meters of the current product. For SAR product, we use Ground Range resolution as we will automatically orthorectify the tiles.

sensor_type#

Sensor type, SAR or optical.

split_name#

Split name, to retrieve every information from its true name (dates, tile, product type…).

property stac: StacItem#
tile_name#

Tile if possible (for data that can be piled, for example S2 and Landsats).