Python API Reference¶
This page documents the stable public imports for spectral-library.
Stable Imports¶
from spectral_library import (
BandInput,
BatchMappingArrayResult,
BatchMappingResult,
HyperspectralLibraryInput,
MappingInputError,
MappingResult,
PreparedRuntime,
PreparedLibraryCompatibilityError,
PreparedLibraryManifest,
PreparedLibraryValidationError,
SensorInput,
SensorSRFSchema,
SpectralLibraryError,
SpectralMapper,
benchmark_mapping,
build_mapping_library,
build_mapping_runtime,
coerce_sensor_input,
prepare_mapping_library,
validate_prepared_library,
)
The repository is also organized into four package areas:
spectral_library.mappingpublic mapping runtime, prepared-runtime build, and retrieval enginespectral_library.distributionruntime download helpersspectral_library.sourcesmaintainer-oriented source acquisition and catalog toolsspectral_library.normalizationmaintainer-oriented normalization and SIAC package-export tools
The stable public contract is centered on the root spectral_library imports
above plus the documented spectral_library.distribution helpers.
Public Workflow¶
0. download_prepared_library(...)¶
Download a pre-built prepared runtime from GitHub Releases or a direct URL.
from pathlib import Path
from spectral_library.distribution import RuntimeDownloadError, download_prepared_library
output = download_prepared_library(
Path("build/mapping_runtime"),
# tag="v0.6.3", # optional: pin to a specific release
# url="https://...", # optional: direct tarball URL
# sha256="abc123...", # optional: expected digest
)
Returns:
Pathto the extracted runtime directory
Raises:
RuntimeDownloadErrorwhen the download, verification, or extraction fails
0a. resolve_prepared_library_root(...)¶
Resolve the published default runtime or return an explicit override path.
from spectral_library.distribution import resolve_prepared_library_root
prepared_root = resolve_prepared_library_root()
custom_root = resolve_prepared_library_root("build/mapping_runtime")
When called without an argument, this helper resolves the package-matched published runtime into the user cache and reuses it on later calls. Pass an explicit path to bypass the default cache and use your own prepared runtime.
1. build_mapping_library(...)¶
Build the prepared runtime used by mapping.
from pathlib import Path
from spectral_library import build_mapping_library
manifest = build_mapping_library(
siac_root=Path("build/siac_spectral_library_real_full_raw_no_ghisacasia_no_understory_no_santa37"),
srf_root=None,
output_root=Path("build/official_mapping_runtime"),
source_sensors=["terra_modis", "sentinel-2a_msi", "landsat-8_oli", "landsat-9_oli2"],
knn_index_backends=["faiss"],
)
Built-in sensors now use canonical rsrf ids directly, such as
sentinel-2a_msi, sentinel-2b_msi, sentinel-2c_msi, landsat-8_oli,
landsat-9_oli2, terra_modis, snpp_viirs, noaa-20_viirs, and
noaa-21_viirs. Pass srf_root=Path(...) only when you need extra local
sensor JSON definitions. Those local files must be valid
rsrf_sensor_definition documents, and any mapping-specific segment metadata
must live in bands[].extensions.spectral_library.segment. Built-in canonical
sensor resolution now targets rsrf>=0.3.1; first use may bootstrap canonical
runtime data into the local rsrf cache automatically. Set RSRF_ROOT only
to override that with a specific checkout or mirrored runtime root, and preseed
RSRF_CACHE_DIR when you need the same flow without network access.
Returns:
PreparedLibraryManifest
Raises:
PreparedLibraryBuildErrorviaSpectralLibraryErrorSensorSchemaErrorviaSpectralLibraryError
prepare_mapping_library(...) remains available as a compatibility alias with
the same signature and return type.
2. build_mapping_runtime(...)¶
Build a reusable mapping runtime directly from in-memory arrays and sensor input definitions.
import numpy as np
from spectral_library import (
BandInput,
HyperspectralLibraryInput,
SensorInput,
build_mapping_runtime,
)
wavelengths = np.arange(400.0, 2501.0, 1.0, dtype=np.float64)
spectra = np.vstack(
[
np.full(wavelengths.shape, 0.10, dtype=np.float32),
np.full(wavelengths.shape, 0.20, dtype=np.float32),
]
)
with build_mapping_runtime(
library=HyperspectralLibraryInput(
wavelengths_nm=wavelengths,
spectra=spectra,
sample_ids=["sample_a", "sample_b"],
),
source_sensors=[
SensorInput(
sensor_id="source_sensor",
bands=[
BandInput(band_id="blue", center_wavelength_nm=490.0, fwhm_nm=20.0),
],
)
],
target_sensors=[
SensorInput(
sensor_id="target_sensor",
bands=[
BandInput(band_id="green", center_wavelength_nm=560.0, fwhm_nm=20.0),
],
)
],
) as runtime:
result = runtime.map_reflectance(
source_sensor="source_sensor",
reflectance={"blue": 0.12},
output_mode="target_sensor",
target_sensor="target_sensor",
)
Returns:
PreparedRuntime
Raises:
PreparedLibraryBuildErrorviaSpectralLibraryErrorSensorSchemaErrorviaSpectralLibraryError
3. coerce_sensor_input(...)¶
Normalize a canonical sensor id, an rsrf_sensor_definition mapping, or a
neutral SensorInput payload into a SensorSRFSchema.
from spectral_library import BandInput, SensorInput, coerce_sensor_input
schema = coerce_sensor_input(
SensorInput(
bands=[
BandInput(center_wavelength_nm=490.0, fwhm_nm=20.0),
BandInput(center_wavelength_nm=1610.0, fwhm_nm=40.0),
]
)
)
Returns:
SensorSRFSchema
Raises:
SensorSchemaErrorviaSpectralLibraryError
4. validate_prepared_library(...)¶
Validate the runtime layout and optionally verify checksums.
from pathlib import Path
from spectral_library import validate_prepared_library
manifest = validate_prepared_library(
Path("build/official_mapping_runtime"),
verify_checksums=True,
)
Returns:
PreparedLibraryManifest
Raises:
PreparedLibraryValidationErrorPreparedLibraryCompatibilityError
5. SpectralMapper¶
Load a prepared runtime and serve mapping requests.
from spectral_library import SpectralMapper
from spectral_library.distribution import resolve_prepared_library_root
mapper = SpectralMapper(resolve_prepared_library_root(), verify_checksums=True)
Public methods:
| Method | Purpose |
|---|---|
get_sensor_schema(sensor_id) |
return the loaded SensorSRFSchema |
compile_linear_mapper(...) |
compile a fixed array-to-array mapper for high-throughput inference |
map_reflectance(...) |
map one source observation on the slim default path |
map_reflectance_debug(...) |
map one source observation and include neighbor/diagnostic payloads |
map_reflectance_batch(...) |
map many observations and return dense arrays on the fast default path |
map_reflectance_batch_debug(...) |
map many observations and return rich MappingResult objects |
map_reflectance_batch_arrays(...) |
explicit alias for the dense batch path |
Single-Sample Example¶
from pathlib import Path
import csv
from spectral_library import SpectralMapper
query_path = Path("examples/official_mapping/queries/single/blue_spruce_needles_terra_modis.csv")
reflectance = {}
with query_path.open("r", encoding="utf-8", newline="") as handle:
for row in csv.DictReader(handle):
reflectance[row["band_id"]] = float(row["reflectance"])
mapper = SpectralMapper(Path("build/official_mapping_runtime"))
result = mapper.map_reflectance(
source_sensor="terra_modis",
reflectance=reflectance,
output_mode="target_sensor",
target_sensor="sentinel-2a_msi",
neighbor_estimator="simplex_mixture",
knn_backend="scipy_ckdtree",
knn_eps=0.05,
exclude_row_ids=[
"usgs_v7:usgs_v7_002183:Blue_Spruce DW92-5 needles BECKa AREF",
],
)
map_reflectance(...) now defaults to the slim result path. If you need
neighbor ids, per-segment diagnostics, or review payloads, call
map_reflectance_debug(...) instead.
Batch Example¶
from spectral_library import SpectralMapper
mapper = SpectralMapper(Path("build/official_mapping_runtime"))
batch = mapper.map_reflectance_batch(
source_sensor="landsat-8_oli",
sample_ids=["blue_spruce_needles", "pale_brown_silty_loam", "tap_water", "asphalt_road"],
reflectance_rows=[
{"ultra_blue": 0.08565344, "blue": 0.08364366, "green": 0.10364797, "red": 0.06556322, "nir": 0.39777808, "swir1": 0.09562342, "swir2": 0.03500909},
{"ultra_blue": 0.05807071, "blue": 0.09366218, "green": 0.19350962, "red": 0.28368705, "nir": 0.36777489, "swir1": 0.48421241, "swir2": 0.45429637},
{"ultra_blue": 0.02863228, "blue": 0.02789226, "green": 0.02699205, "red": 0.02652986, "nir": 0.02617234, "swir1": 0.02100237, "swir2": 0.01889161},
{"ultra_blue": 0.06766724, "blue": 0.07308879, "green": 0.08826971, "red": 0.10323628, "nir": 0.12662063, "swir1": 0.19511989, "swir2": 0.21389012},
],
output_mode="target_sensor",
target_sensor="sentinel-2a_msi",
neighbor_estimator="simplex_mixture",
knn_backend="scipy_ckdtree",
exclude_row_ids_per_sample=[
"usgs_v7:usgs_v7_002183:Blue_Spruce DW92-5 needles BECKa AREF",
"ecostress_v1:ecostress_v1_002334:Pale brown silty loam",
"ecostress_v1:ecostress_v1_003451:Tap water",
"usgs_v7:usgs_v7_000004:Asphalt GDS376 Blck_Road old ASDFRa AREF",
],
)
map_reflectance_batch(...) returns BatchMappingArrayResult by default, so
the main outputs are batch.reflectance, batch.output_columns, and
batch.source_fit_rmse. If you need per-sample MappingResult objects and
diagnostics, call map_reflectance_batch_debug(...).
Supported exclusion controls:
neighbor_estimator="mean","distance_weighted_mean", or"simplex_mixture"knn_backend="numpy","scipy_ckdtree","faiss","pynndescent", or"scann"knn_eps > 0to relax supported ANN searchesmap_reflectance(..., exclude_row_ids=..., exclude_sample_names=...)map_reflectance_batch(..., exclude_row_ids=..., exclude_sample_names=...)map_reflectance_batch(..., exclude_row_ids_per_sample=..., self_exclude_sample_id=True)
That means the public Python API can now reproduce the same held-out self-exclusion workflow shown in Official Sensor Examples.
Optional backend install extras:
python3 -m pip install "spectral-library[knn]"
python3 -m pip install "spectral-library[knn-faiss]"
python3 -m pip install "spectral-library[knn-pynndescent]"
python3 -m pip install "spectral-library[knn-scann]"
High-Throughput Linear Mapper¶
If you need to map millions of pixels and can trade retrieval-style diagnostics for a fixed fast model, compile the prepared runtime into one linear mapper and then apply it to dense arrays in chunks.
import numpy as np
from spectral_library import SpectralMapper
mapper = SpectralMapper(Path("build/official_mapping_runtime"))
linear_mapper = mapper.compile_linear_mapper(
source_sensor="landsat-8_oli",
target_sensor="sentinel-2a_msi",
output_mode="target_sensor",
dtype="float32",
)
pixel_block = np.asarray(
[
[0.08565344, 0.08364366, 0.10364797, 0.06556322, 0.39777808, 0.09562342, 0.03500909],
[0.05807071, 0.09366218, 0.19350962, 0.28368705, 0.36777489, 0.48421241, 0.45429637],
],
dtype=np.float32,
)
mapped = linear_mapper.map_array(pixel_block, chunk_size=65536)
This fast path is intentionally narrow:
- input must be a dense
numpy.ndarrayin source-band order - it returns a plain
numpy.ndarrayinstead ofMappingResultobjects - it is best suited for raster/tile processing with reusable
out=buffers ornumpy.memmapoutputs
Result Objects¶
MappingResult¶
| Field | Meaning |
|---|---|
target_reflectance |
mapped target reflectance values, when applicable |
target_band_ids |
target band ids paired with target_reflectance |
reconstructed_vnir |
reconstructed 400-1000 nm segment |
reconstructed_swir |
reconstructed 800-2500 nm segment |
reconstructed_full_spectrum |
overlap-blended 400-2500 nm reconstruction |
reconstructed_wavelength_nm |
wavelength grid for the requested spectral output |
neighbor_ids_by_segment |
retrieved library row ids for each segment; empty on the slim default path |
neighbor_distances_by_segment |
neighbor distances for each segment; empty on the slim default path |
segment_outputs |
successful segment reconstructions; empty on the slim default path |
segment_valid_band_counts |
number of valid source bands used per segment |
diagnostics |
stable debug payload, including per-segment query values when requested; empty on the slim default path |
Helper:
to_summary_dict()
Use map_reflectance_debug(...) when you need the populated diagnostic fields.
BatchMappingResult¶
Returned by map_reflectance_batch_debug(...).
| Field | Meaning |
|---|---|
sample_ids |
output sample ids in order |
results |
per-sample MappingResult values |
Helper:
to_summary_dict()
BatchMappingArrayResult¶
Returned by map_reflectance_batch(...) and map_reflectance_batch_arrays(...).
| Field | Meaning |
|---|---|
sample_ids |
output sample ids in order |
reflectance |
dense (n_samples, n_outputs) output matrix |
source_fit_rmse |
one scalar source-sensor fit RMSE per sample; lower is better |
output_columns |
output column labels aligned to reflectance[:, j] |
wavelength_nm |
wavelength axis for spectral modes, otherwise None |
Public Error Types¶
All public errors inherit from SpectralLibraryError and carry structured
fields for programmatic handling.
from pathlib import Path
from spectral_library import (
MappingInputError,
PreparedLibraryCompatibilityError,
PreparedLibraryValidationError,
SpectralLibraryError,
SpectralMapper,
validate_prepared_library,
)
# Catch all spectral-library errors
try:
manifest = validate_prepared_library(Path("build/mapping_runtime"))
except PreparedLibraryCompatibilityError as exc:
print(f"Runtime was built with an incompatible schema: {exc.message}")
print(f"Context: {exc.context}")
except PreparedLibraryValidationError as exc:
print(f"Runtime validation failed: {exc.message}")
except SpectralLibraryError as exc:
print(f"[{exc.code}] {exc.message}")
# Handle mapping-specific errors
mapper = SpectralMapper(Path("build/mapping_runtime"))
try:
result = mapper.map_reflectance(
source_sensor="terra_modis",
reflectance={"blue": 0.08, "nir": 0.34},
output_mode="target_sensor",
target_sensor="sentinel-2a_msi",
)
except MappingInputError as exc:
# Structured error for logging or API responses
error_dict = exc.to_dict(command="map_reflectance")
print(error_dict)
# {"error_code": "invalid_mapping_input", "message": "...", "command": "map_reflectance", "context": {...}}
Public error types¶
| Class | error_code |
Raised when |
|---|---|---|
SpectralLibraryError |
(varies) | Base class for all package errors |
SensorSchemaError |
invalid_sensor_schema |
Sensor schema data from rsrf or local JSON is malformed or unavailable |
PreparedLibraryBuildError |
prepare_failed |
Runtime build fails |
PreparedLibraryValidationError |
invalid_prepared_library |
Runtime layout or checksums are invalid |
PreparedLibraryCompatibilityError |
prepared_library_incompatible |
Schema version mismatch |
MappingInputError |
invalid_mapping_input |
Invalid query input |
Every public error carries:
code- machine-readable error code stringmessage- human-readable descriptioncontext- dict with additional diagnostic fieldsto_dict(command=...)- serialize to a structured dict
Public Data Models¶
PreparedLibraryManifest¶
Represents the stable prepared-runtime manifest returned by:
build_mapping_library(...)validate_prepared_library(...)
Current prepared runtimes also expose interpolation_summary so you can see how
many SIAC rows required gap repair during build. When requested at build
time, they also expose knn_index_artifacts so you can see which persisted ANN
indexes were written into the runtime.
Debug diagnostics expose a heuristic confidence_score at the overall mapping
level and per segment. This is not a calibrated uncertainty model; it is a
compact ranking signal derived from distance, source fit, weight
concentration, and valid-band coverage. The diagnostics also include
confidence_policy, which currently maps the score to:
high/acceptfor scores>= 0.85medium/manual_reviewfor scores>= 0.60and< 0.85low/rejectfor scores< 0.60
benchmark_mapping(...) also accepts max_test_rows so large prepared
libraries can run bounded held-out evaluations without scoring every row in the
test split.
SensorSRFSchema¶
Represents one public sensor JSON schema in memory, backed by the rsrf
sensor-definition contract. Custom sensor JSON files should be serialized as
rsrf_sensor_definition documents with
bands[].extensions.spectral_library.segment.
The runtime format itself is documented in Prepared Runtime Contract.