NISAR Data Access¶
This notebook demonstrates how to access and explore NISAR data in Python. NISAR products are distributed as HDF5 files, which can be opened using several different tools depending on the level of detail and functionality needed.
After searching for and downloading NISAR data, this workflow:
accesses data using
h5pyaccesses data using
xarray.Datasetandxarray.DataTreeaccesses data using
ISCE3
These approaches highlight different options for accessing NISAR data, allowing users to compare methods based on their research questions and workflow.
Notebook Overview¶
1. Prerequisites¶
| Prerequisite | Importance | Notes |
|---|---|---|
| The software environment for this cookbook must be installed | Necessary |
Rough Notebook Time Estimate: 10 minutes
2. Comparing Methods for Accessing NISAR Data¶
The approaches shown in this notebook provide different ways to access and work with NISAR HDF5 files, each with its own strengths.
| Method | Best For | Pros | Cons |
|---|---|---|---|
| h5py | Direct, low-level file access | Minimal dependencies, full control over HDF5 structure, can inspect datasets without loading values | Requires long paths, manual navigation, slicing loads data immediately into memory |
| xarray.Dataset | Working with one HDF5 group | Labeled arrays, cleaner syntax, easier data handling, supports lazy loading with chunked arrays for large datasets | Opens one group at a time, requires knowing the group path |
| xarray.Datatree | Working with multiple HDF5 groups | Preserves full HDF5 structure, supports lazy loading with chunking, useful for navigating unknown files and working across multiple groups | More complex, less efficient for single group analysis |
| ISCE3 | SAR processing and NISAR-specific workflows | Designed for NISAR data, understands radar geometry and metadata | Does not easily pull all types of metadata, requires additional installation, may not work in all environments |
3. Selecting a NISAR Product¶
NISAR products are identified by a four-letter abbreviation. In the download example below, the product type is controlled by the processingLevel field. To learn more about invidicual products, see the NISAR Data User Guide.
For this walkthrough, we use:
GCOV — Geocoded Polarimetric Covariance Matrix
Other NISAR products include:
L0 Products¶
RRSD — Radar Raw Signal Data
L1 Products¶
RSLC — Range-Doppler Single Look Complex
RIFG — Range-Doppler Interferogram
ROFF — Range-Doppler Pixel Offsets
RUNW — Range-Doppler Unwrapped Interferogram
L2 Products¶
GSLC — Geocoded Single Look Complex
GOFF — Geocoded Pixel Offsets
GCOV — Geocoded Polarimetric Covariance Matrix
GUNW — Geocoded Unwrapped Interferogram
L3 Products¶
SME2 — Soil Moisture
To search for a different NISAR product, replace "GCOV" in the processingLevel field with the four-letter abbreviation for your product of interest.¶
4. Download a NISAR HDF5 file¶
4a. Search for NISAR data. For this examlpe, we will use a GCOV data.¶
import os
import asf_search as asf
from datetime import datetime
from getpass import getpass
from pathlib import Path
# authenticate with Earthdata Login
session = asf.ASFSession()
session.auth_with_creds(input('EDL Username'), getpass('EDL Password'))
# insert start and end dates. Note that dates and times are inclusive.
start_date = datetime(2025, 12, 4)
end_date = datetime(2025, 12, 5)
area_of_interest = "POLYGON((40.9131 12.3904,41.8891 12.3904,41.8891 13.2454,40.9131 13.2454,40.9131 12.3904))"
opts = asf.ASFSearchOptions(
**{
"maxResults": 250, # limit the number of returned results
"intersectsWith": area_of_interest, # spatial filter (WKT geometry)
"start": start_date, # temporal filter (start)
"end": end_date, # temporal filter (end)
# to switch NISAR products, change the four letter abbreviation next to processingLevel
"processingLevel": ["GCOV"], # product type / processing level
"dataset": ["NISAR"], # mission/dataset name
"productionConfiguration": ["PR"], # production config (e.g., provisional)
"session": session, # use authenticated session from above
}
)
response = asf.search(opts=opts)
pattern = r'^(?!.*QA_STATS).*'
h5_files = response.find_urls(extension='.h5', pattern=pattern, directAccess=False)
h5_filesEDL Username jwhite124
EDL Password ········
['https://nisar.asf.earthdatacloud.nasa.gov/NISAR/NISAR_L2_GCOV_BETA_V1/NISAR_L2_PR_GCOV_006_172_A_008_2005_DHDH_A_20251204T024618_20251204T024653_X05007_N_F_J_001/NISAR_L2_PR_GCOV_006_172_A_008_2005_DHDH_A_20251204T024618_20251204T024653_X05007_N_F_J_001.h5',
'https://nisar.asf.earthdatacloud.nasa.gov/NISAR/NISAR_L2_GCOV_BETA_V1/NISAR_L2_PR_GCOV_006_172_A_008_2005_DHDH_A_20251204T024618_20251204T024653_X05009_N_F_J_001/NISAR_L2_PR_GCOV_006_172_A_008_2005_DHDH_A_20251204T024618_20251204T024653_X05009_N_F_J_001.h5']4b. Download the data¶
data_dir = Path.home() / "NISAR_data_access_example"
data_dir.mkdir(exist_ok=True)
print(f'data_dir: {data_dir}')
#download files
asf.download_urls(h5_files, data_dir, session=session, processes=4)data_dir: /home/jovyan/NISAR_data_access_example
5. Opening NISAR Data with h5py¶
The h5py library allows you to access HDF5 files directly in Python. NISAR products are stored as hierarchical datasets, similar to folders and files.
In this example, we open a NISAR file, navigate to the metadata group, read the incidenceAngle dataset and print the shape.
First, we inspect the dataset shape without loading the data values into memory. Then, we load the full dataset using [:]. Finally, we read a smaller subset and calculate its mean.
Note: In h5py, accessing a dataset object does not load the data values into memory. Data are loaded when values are explicitly accessed, such as with [:] or slicing. Once sliced, the result is loaded into memory as a NumPy array.
5a. Inspect dataset without loading into memory¶
%%time
import h5py
h5_h5py = list(data_dir.glob("NISAR_L2_*_GCOV*.h5"))[0]
with h5py.File(h5_h5py, "r") as f:
incidence = f["/science/LSAR/GCOV/metadata/radarGrid/incidenceAngle"]
print("incidenceAngle shape:", incidence.shape)incidenceAngle shape: (21, 680, 695)
CPU times: user 22.1 ms, sys: 0 ns, total: 22.1 ms
Wall time: 21 ms
5b. Full load: read dataset into memory¶
%%time
import h5py
h5_h5py = list(data_dir.glob("NISAR_L2_*_GCOV*.h5"))[0]
with h5py.File(h5_h5py, "r") as f:
incidence = f["/science/LSAR/GCOV/metadata/radarGrid/incidenceAngle"][:]
print("incidenceAngle shape:", incidence.shape)incidenceAngle shape: (21, 680, 695)
CPU times: user 135 ms, sys: 49.3 ms, total: 184 ms
Wall time: 183 ms
5c. Subset and compute mean¶
Note: The subset mean is used here only to demonstrate how data are loaded and processed. Because incidenceAngle is a 3D metadata grid, scientific interpretation should be done carefully, usually for a specific height level and spatial region.
%%time
# Subset load: read one height level and a small spatial subset, then compute a statistic
import h5py
import numpy as np
h5_h5py = list(data_dir.glob("NISAR_L2_*_GCOV*.h5"))[0]
with h5py.File(h5_h5py, "r") as f:
incidence = f["/science/LSAR/GCOV/metadata/radarGrid/incidenceAngle"]
subset = incidence[0, 0:100, 0:100]
subset_mean = np.nanmean(subset)
print("subset mean:", subset_mean)subset mean: 46.621464
CPU times: user 5.14 ms, sys: 3.12 ms, total: 8.25 ms
Wall time: 7.67 ms
6. Opening NISAR Data with xarray.Dataset and xarray.DataTree¶
The xarray package provides tools for working with labeled arrays. Here, we show two xarray data structures:
xarray.Dataset: useful when opening one specific group in a NISAR HDF5 file.xarray.DataTree: useful when opening the full hierarchical file structure.
Both can support lazy loading workflows when opened with chunks={}.
6a. Opening NISAR Data with xarray.Dataset¶
Here, we open the NISAR metadata radarGrid group as an xarray.Dataset. This lets us access variables in the group, such as incidenceAngle, using shorter variable names.
We open the dataset with Dask chunking, chunks={}, which creates a Dask-backed xarray object. This allows operations to be queued without immediately loading the full array into memory. Although 8 MB chunks are generally recommended for larger NISAR direct-access workflows, the incidenceAngle dataset is small enough that the native chunk layout is sufficient.
For additional benchmarking and recommendations for NISAR direct-access workflows, see Henry Rodman’s Reading NISAR granules directly from S3.
Note that open_dataset only works for one group at a time. When accessing more than one group, use open_datatree.
# Ignore warnings
import warnings
warnings.filterwarnings("ignore")
import xarray as xr
h5_xarray = list(data_dir.glob("NISAR_L2_*_GCOV*.h5"))[0]
ds = xr.open_dataset(
h5_xarray,
group="/science/LSAR/GCOV/metadata/radarGrid",
chunks={}
)
incidence = ds["incidenceAngle"]
print("incidenceAngle shape:", incidence.shape)
incidenceincidenceAngle shape: (21, 680, 695)
Here, we select one height level and a small spatial subset, then calculate the mean. This operation is queued, but not computed yet.
%%time
subset_mean = (
ds["incidenceAngle"]
.isel(heightAboveEllipsoid=0, yCoordinates=slice(0, 100), xCoordinates=slice(0, 100))
.mean()
)
subset_meanCPU times: user 4.51 ms, sys: 0 ns, total: 4.51 ms
Wall time: 3.92 ms
Calling .compute() triggers the actual read and calculation.
%%time
subset_mean_value = subset_mean.compute()
print("subset mean:", subset_mean_value.values)subset mean: 46.621464
CPU times: user 92.7 ms, sys: 28.6 ms, total: 121 ms
Wall time: 121 ms
ds.close()6b. Opening NISAR Data with xarray DataTree¶
An xarray.DataTree preserves the full hierarchical structure of the NISAR HDF5 file. This is useful when you want to work across multiple groups.
Here, we open the full file as a tree-like object and access the same incidenceAngle dataset through its group path.
# Ignore warnings
import warnings
warnings.filterwarnings("ignore")
import xarray as xr
h5_datatree = list(data_dir.glob("NISAR_L2_*_GCOV*.h5"))[0]
dt = xr.open_datatree(
h5_datatree,
engine="h5netcdf",
chunks={}
)
incidence = dt["/science/LSAR/GCOV/metadata/radarGrid"]["incidenceAngle"]
print("incidenceAngle shape:", incidence.shape)
dtincidenceAngle shape: (21, 680, 695)
dt.close()7. ISCE3¶
The NISAR product reader (part of ISCE3) provides a more complex interface for working with NISAR data. It understands the structure of NISAR products and includes built-in attributes and methods for accessing product information and image datasets.
Unlike h5py and xarray, which access datasets directly through the HDF5 structure, ISCE3 interacts with the data through class methods and member variables.
7a. Opening NISAR Metadata with ISCE3¶
In this example, we first access general product information, polarizations metadata, using reader member variables.
These values come from the product metadata, but are accessed differently than in the previous examples. Instead of navigating the file structure (as with h5py or xarray), ISCE3 exposes selected metadata through object attributes.
While some metadata can be accessed this way, many metadata datasets (such as incidenceAngle) are not available through a simple or consistent interface in ISCE3. For this reason, h5py or xarray may be more ideal for accessing metadata.
from nisar.products.readers import open_product
h5_isce3 = list(data_dir.glob("NISAR_L2_*.h5"))[0]
product = open_product(h5_isce3)
print("polarizations:", product.polarizations)polarizations: {'A': ['HH', 'HV'], 'B': ['HH', 'HV']}
7b. Using ISCE3 to read image data¶
Next, we use the ISCE3 reader to access an image dataset using the getImageDataset() method.
This method provides a convenient way to access image layers (such as polarization datasets), which are central to many SAR and NISAR workflows. This type of access is a more common use of ISCE3, as it is designed to work with image data and SAR-specific processing rather than general metadata retrieval.
from nisar.products.readers import open_product
h5_hvhv = list(data_dir.glob("NISAR_L2_*_GCOV*.h5"))[0]
hvhv_data = open_product(h5_hvhv)
hvhv = hvhv_data.getImageDataset(frequency="A", polarization="HVHV")
print("HVHV shape:", hvhv[:, :].shape)HVHV shape: (16704, 17064)
9. Resources and references¶
Authors: Julia White, Alex Lewandowski