Optical#

easysnowdata.optical#

Optical (passive, visible through SWIR and thermal) imagery.

The name pairs with easysnowdata.sar (active microwave) and covers every sensor in the theme, including thermal-only and hyperspectral products that are not multispectral (plan §3.1). Band math, masks and composites live in easysnowdata.processing.optical; the loaders here only add product knowledge: collection ids, band aliases, nodata, scaling and citations.

easysnowdata.optical.hls#

Harmonized Landsat Sentinel-2 (HLS) v2.0.

Sources (companion file §B.3):

lpcloud-cmr-stac (default)

NASA’s CMR-STAC LPCLOUD catalog: HLSL30_2.0 (Landsat 8/9) and HLSS30_2.0 (Sentinel-2), the archive of record, same-day with the LP DAAC. The search is open; the COG reads are behind Earthdata Login, so they go through the earthdata provider’s GDAL environment (netrc plus a cookie jar, or a bearer token), which Dask workers inherit.

planetary-computer

hls2-l30 / hls2-s30: a credential-free mirror, ids verified live on 2026-09-16 (the plan could not check them during the PC outage).

Scene metadata comes from STAC properties, not from the per-granule XML the old HLS class fetched one request at a time:

import easysnowdata as esd
items = esd.optical.hls.search(aoi, "2023-08", cloud_cover=40)
hls = esd.optical.hls.load(aoi, "2023-08", mask="fmask-default")

load returns one Dataset with both products stacked on time and a product coordinate (L30/S30) saying where each scene came from.

search

Search both HLS products and return the items as one GeoDataFrame.

load

Load HLS as a lazy xarray.Dataset (time, y, x).

easysnowdata.optical.planetscope#

PlanetScope (and SkySat) imagery from Planet Labs.

Planet is the first key-gated commercial source in the package (plan §12 Q17, companion §B.11). Two routes, and the difference is quota:

orders-api (default)

Search with the Data API, then order the scenes with the clip tool so Planet delivers COGs cut to the AOI, optionally harmonize``d to Sentinel-2. An order is charged for the clipped area only. Because an order spends quota it is never implicit: :func:`load` refuses to place one unless ``order=True, and order() is the explicit entry point.

data-api

Activate and read a whole scene’s asset directly. This is the quick-look route for a single scene; activation charges the full scene area, and the AOI is only applied after the bytes have been streamed.

import easysnowdata as esd
scenes = esd.optical.planetscope.search(aoi, "2023-07-01/2023-07-02")
order = esd.optical.planetscope.order(aoi, items=scenes.head(1))   # spends quota
ps = esd.optical.planetscope.load(aoi, order=order)
udm2 = esd.processing.decode_udm2(ps["udm2"])                      # snow band

Planet imagery is not redistributable, so nothing in this repository contains a real scene: the tests run on synthetic deliveries and scrubbed Data API responses.

search

Search the Planet Data API and return the scenes as a GeoDataFrame.

order

Order scenes clipped to aoi and (by default) wait for and download them.

load

Load PlanetScope imagery as an xarray.Dataset (time, y, x).

open_delivery

Open delivered Planet COGs (a directory, file list, or order result).

easysnowdata.optical.sentinel2#

Sentinel-2 Level-2A surface reflectance.

Sources (companion file §B.2):

planetary-computer (default)

sentinel-2-l2a on Microsoft Planetary Computer: credential-free (hrefs are signed for you), one catalog for Sentinel-1, Sentinel-2, the DEM and WorldCover. Its items historically carry no raster:bands, so the band aliases and dtypes come from a stac_cfg fallback and the post-2022-01-25 baseline offset is undone by the date rule.

earth-search

Element 84’s sentinel-2-l2a, sentinel-2-c1-l2a and sentinel-2-pre-c1-l2a on AWS: unsigned S3, assets already named by common band name, and items that carry raster:bands with scale and offset — so the baseline offset is applied from metadata rather than from a date.

import easysnowdata as esd
items = esd.optical.sentinel2.search(aoi, "2024-05", cloud_cover=30)
s2 = esd.optical.sentinel2.load(aoi, "2024-05", mask="scl-default")
ndsi = esd.processing.ndsi(s2)

load returns reflectance (scaled, harmonized to the pre-2022 baseline) with dims time, y, x in the AOI’s UTM zone.

search

Search one of the catalogs and return the items as a GeoDataFrame.

load

Load Sentinel-2 L2A as a lazy xarray.Dataset (time, y, x).