- Home
- Documentation
- API reference
- Core
- hyperproc.io
hyperproc.io¶
Source-derived reference
Generated from the current hyperproc 0.1.2 checkout.
Implementation: hyperproc/io.py. Signatures, defaults, docstrings, and expandable source are extracted statically; the module is not imported or executed. Names beginning with _ are implementation details, not a stable public API.
Use the function signature as the authority for individual parameter defaults and return annotations. Original docstrings sometimes group parameter names or wrap return descriptions across lines; these descriptions are preserved rather than inferred or rewritten.
Writing cubes back out to disk.
_CUBE_VARS = ('reflectance', 'radiance')
module-attribute
¶
FORMATS = {'GTiff': '.tif', 'ENVI': '.img'}
module-attribute
¶
INTERLEAVES = ('bil', 'bip', 'bsq')
module-attribute
¶
GEOMETRY_LAYERS = ('slope', 'aspect', 'cos_i', 'sza', 'saa', 'vza', 'vaa', 'raa', 'elev', 'path_length')
module-attribute
¶
main_var(ds: xr.Dataset) -> str
¶
Name of the dataset's cube variable (reflectance or radiance).
Source code in hyperproc/io.py
default_name(ds: xr.Dataset, suffix: str = '', ext: str = '.tif') -> str
¶
<stem><suffix><ext> - the source filename with .nc swapped out.
Most sensors carry the level in the granule id already
(EMIT_L2A_RFL_...), so granule is enough to name a file uniquely.
AVIRIS ids do not - AV320231005t181518 is the flight line, shared by
L1B and L2A - and the two levels do not always agree: AVIRIS-3 ships a
bbl on L2A and none on L1B, so their band tables genuinely differ.
Readers in that position set attrs["stem"] to disambiguate rather than
let the second write silently replace the first.
Source code in hyperproc/io.py
_resolve(path: str | Path, ds: xr.Dataset, suffix: str = '', ext: str = '.tif') -> Path
¶
Accept either a full file path or a directory to name the file inside.
Source code in hyperproc/io.py
_transform_for(ds: xr.Dataset)
¶
The affine to write, rebuilt from the dataset's own x/y coordinates.
attrs["transform"] describes the granule as delivered, so it goes stale
the moment anyone subsets. rioxarray normally sidesteps that by deriving
the affine from the coordinates - but it cannot for the flight-aligned
AVIRIS grids, where rotation makes easting depend on the row as well as the
column, and it falls back to a north-up transform that puts the image in
the wrong place.
So: take the rotation and pixel size from attrs["transform"], and
recover the origin from where the coordinates actually start. The 1-D
x/y are written as gt[0] + (col + 0.5) * gt[1] and
gt[3] + (row + 0.5) * gt[5], so inverting them gives the subset's
offset exactly, and their spacing gives any stride.
Returns None when there is nothing better than rioxarray's own guess.
Source code in hyperproc/io.py
envi_header(ds: xr.Dataset, var: str | None = None) -> dict
¶
The spectral fields an ENVI header carries and a GeoTIFF cannot.
A GeoTIFF can only label a band with free text, so 650.4 nm is a
description a human reads. An ENVI header states wavelength, fwhm
and bbl as fields that ENVI, Spectronon and this package's own readers
parse back into numbers. That is the reason to write ENVI at all.
bbl follows ENVI's convention: 1 for a usable band, 0 for one to
ignore, taken from good_wavelength. Exporting a bad-band list is
something the GeoTIFF route cannot do.
Source code in hyperproc/io.py
_write_cube(ds: xr.Dataset, path, var, driver: str, compress, overviews, overview_resampling: str, interleave: str | None) -> Path
¶
Shared writer for every format: CRS, streaming, band labels, metadata.
The streaming rules here were expensive to find and are format independent, so both writers use them rather than keeping two copies that drift.
Source code in hyperproc/io.py
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | |
to_geotiff(ds: xr.Dataset, path: str | Path, var: str | None = None, compress: str = 'deflate', overviews: bool | list[int] | None = None, overview_resampling: str = 'average') -> Path
¶
Write a cube to a multi-band GeoTIFF, one band per wavelength.
Band descriptions are set to the wavelength in nm, so QGIS and ArcGIS show
650.4 nm rather than Band 12. With overviews the file also gets
internal pyramids (what QGIS's Build Overviews does), so a GIS can draw the
whole cube without reading it at full resolution.
For a header that states the wavelengths as numbers rather than as band
labels, and that can carry a bad-band list, see :func:to_envi.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
dataset from :func:
TYPE:
|
path
|
output
TYPE:
|
var
|
which variable to write. Defaults to the cube variable.
TYPE:
|
compress
|
GeoTIFF compression.
TYPE:
|
overviews
|
TYPE:
|
overview_resampling
|
how overview pixels are computed -
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The path written. |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
the dataset is on the sensor grid and has no CRS. |
Source code in hyperproc/io.py
to_envi(ds: xr.Dataset, path: str | Path, var: str | None = None, interleave: str = 'bil') -> Path
¶
Write a cube to an ENVI flat binary with its .hdr.
The reason to choose this over :func:to_geotiff is the header. It states
wavelength, fwhm and bbl as fields, so ENVI, Spectronon and this
package's own readers recover the band centres, widths and bad-band list as
numbers. A GeoTIFF can only carry them as band labels, and cannot carry a
bad-band list at all.
The costs are real. ENVI has no compression, so a full EMIT product is about 5.1 GB here against 2.2 GB as a deflated GeoTIFF, and it has no internal pyramids, so a GIS redraws from full resolution.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
dataset from :func:
TYPE:
|
path
|
output
TYPE:
|
var
|
which variable to write. Defaults to the cube variable.
TYPE:
|
interleave
|
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The path of the binary. The header is |
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
no CRS, or an unknown interleave. |
Source code in hyperproc/io.py
to_raster(ds: xr.Dataset, path: str | Path, format: str = 'GTiff', **kwargs) -> Path
¶
Write a cube in either format. format is "GTiff" or "ENVI".
A single door for code that takes the format as a setting; the keyword
arguments are those of :func:to_geotiff or :func:to_envi.
Source code in hyperproc/io.py
build_overviews(path: str | Path, factors: list[int] | None = None, resampling: str = 'average', compress: str | None = 'deflate', min_size: int = 256) -> list[int]
¶
Add internal overview pyramids to an existing GeoTIFF.
This is what QGIS's Raster > Miscellaneous > Build Overviews (Pyramids)
and gdaladdo do: reduced-resolution copies of every band are appended
to the file so a viewer can draw it zoomed out without decoding the full
cube. The pyramids are compressed like the main image, band-interleaved,
and built on all cores. Nodata (NaN) pixels are left out of the averages.
| PARAMETER | DESCRIPTION |
|---|---|
path
|
GeoTIFF to modify in place (the main image is untouched).
TYPE:
|
factors
|
reduction factors, e.g.
TYPE:
|
resampling
|
any :class:
TYPE:
|
compress
|
compression for the overview levels;
TYPE:
|
min_size
|
stops the default factor list.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[int]
|
The factors built (empty if the image is already smaller than |
list[int]
|
|
list[int]
|
compression; reading the overviews of band 1 back is |
list[int]
|
|
Source code in hyperproc/io.py
to_geotiff_2d(ds: xr.Dataset, path: str | Path, var: str, overviews: bool | list[int] | None = None, overview_resampling: str = 'average', tags: dict | None = None, format: str = 'GTiff') -> Path
¶
Write a single 2-D layer (sza, elev, cloud, ...) to GeoTIFF.
path may be a directory, in which case the file is named
<granule>_<var>.tif. tags are written as GeoTIFF metadata, which is
how a flag layer carries its own bit meanings.
Source code in hyperproc/io.py
export_geometry(ds: xr.Dataset, path: str | Path, layers: tuple[str, ...] | None = None, overviews: bool | list[int] | None = None, overview_resampling: str = 'average') -> list[Path]
¶
Write the geometry layers a topographic correction needs, one GeoTIFF each.
Saves looping :func:to_geotiff_2d by hand and, more to the point, saves
guessing which layers matter: :data:GEOMETRY_LAYERS is the set SCS+C, the
C-correction and a BRDF fit actually read - slope and aspect for the facet,
cos_i for the illumination, the four angles for the kernels, elevation
and path length for the atmosphere.
Whatever the dataset does not carry is skipped rather than faked, so the return value is the honest list of what exists for this granule.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
dataset from :func:
TYPE:
|
path
|
output directory. Files are named
TYPE:
|
layers
|
override the default set.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
list[Path]
|
The paths written, in the order attempted. |
Source code in hyperproc/io.py
bands_to_csv(ds: xr.Dataset, path: str | Path) -> Path
¶
Write the band table: wavelength, fwhm, good_band.
One row per band, in the same order as the GeoTIFF from :func:to_geotiff,
so row N is band N in the raster. That holds after wl_range
subsetting too, since both are written from the same dataset.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
dataset from :func:
TYPE:
|
path
|
output
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path
|
The path written. |
Note
good_band is True/False from the sensor's own flag. EMIT
ships it on L2A only, so on an L1B granule the column is written empty
rather than guessed.
Source code in hyperproc/io.py
_write_stats(path: Path) -> None
¶
Embed per-band min/max/mean/std.
Without these GDAL reports no statistics and QGIS falls back to a default stretch, which for values like latitude 37.1 or longitude -80.9 renders as a blank or solid-black layer.
Source code in hyperproc/io.py
_spatial_da(arr: np.ndarray, ds: xr.Dataset, projected: bool)
¶
Wrap a (band, y, x) array, carrying the dataset's grid so the GeoTIFF gets a real transform. Without the coords rioxarray writes the identity matrix and the raster lands at the CRS origin instead of the scene.
Source code in hyperproc/io.py
to_latlon_geotiff(ds: xr.Dataset, path: str | Path, separate: bool = False, overviews: bool | list[int] | None = None, overview_resampling: str = 'average') -> Path | tuple[Path, Path]
¶
Write a 2-band GeoTIFF of latitude and longitude - prismaread's LATLON.
Band 1 is latitude, band 2 longitude, both WGS-84 degrees. For a projected
dataset the values are computed from the CRS and grid, so they are exact and
available whether or not the granule shipped geolocation arrays. For an
unprojected swath the granule's own lat/lon are written instead, and
the file carries no CRS - the same thing prismaread does.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
dataset from :func:
TYPE:
|
path
|
output
TYPE:
|
separate
|
write two single-band files,
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Path | tuple[Path, Path]
|
The path written, or both paths when |
Source code in hyperproc/io.py
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 | |