@@ -50,21 +50,21 @@ def read_tanager(filepath, bands=None, stac_url=None, **kwargs):
5050 data = data [bands ]
5151
5252 coords = {
53- "band" : np .arange (data .shape [0 ]),
54- "wavelength" : ("band" , wavelengths ),
55- "fwhm" : ("band" , fwhm ),
53+ "wavelength" : wavelengths ,
54+ "fwhm" : ("wavelength" , fwhm ),
5655 "latitude" : (("y" , "x" ), lat ),
5756 "longitude" : (("y" , "x" ), lon ),
5857 }
5958
60- da = xr .DataArray (data , dims = ("band" , "y" , "x" ), coords = coords , name = "toa_radiance" )
59+ da = xr .DataArray (
60+ data , dims = ("wavelength" , "y" , "x" ), coords = coords , name = "toa_radiance"
61+ )
6162
6263 ds = xr .Dataset (
6364 data_vars = {"toa_radiance" : da },
6465 coords = {
65- "band" : da .band ,
66- "wavelength" : ("band" , wavelengths ),
67- "fwhm" : ("band" , fwhm ),
66+ "wavelength" : da .wavelength ,
67+ "fwhm" : ("wavelength" , fwhm ),
6868 "latitude" : (("y" , "x" ), lat ),
6969 "longitude" : (("y" , "x" ), lon ),
7070 },
@@ -78,13 +78,14 @@ def read_tanager(filepath, bands=None, stac_url=None, **kwargs):
7878 return ds
7979
8080
81- def grid_tanager (dataset , bands = None , method = "nearest" , ** kwargs ):
81+ def grid_tanager (dataset , bands = None , wavelengths = None , method = "nearest" , ** kwargs ):
8282 """
8383 Grids a Tanager dataset based on latitude and longitude.
8484
8585 Args:
8686 dataset (xr.Dataset): The Tanager dataset to grid.
87- bands (list): The bands to select.
87+ bands (list, optional): The band indices to select. Defaults to None.
88+ wavelengths (list, optional): The wavelength values to select. Takes priority over bands. Defaults to None.
8889 method (str, optional): The method to use for griddata interpolation.
8990 Defaults to "nearest".
9091 **kwargs: Additional keyword arguments to pass to the xr.Dataset constructor.
@@ -95,26 +96,52 @@ def grid_tanager(dataset, bands=None, method="nearest", **kwargs):
9596 from scipy .interpolate import griddata
9697 from scipy .spatial import ConvexHull
9798
98- if bands is None :
99- bands = dataset .coords ["band" ].values [0 ]
100-
101- # Ensure wavelengths is a list
102- if not isinstance (bands , list ):
103- bands = [bands ]
99+ # Priority: wavelengths > bands > default
100+ if wavelengths is not None :
101+ # Use wavelengths directly
102+ if not isinstance (wavelengths , list ):
103+ wavelengths = [wavelengths ]
104+ selected_wavelengths = wavelengths
105+ elif bands is not None :
106+ # Convert bands to wavelengths
107+ if not isinstance (bands , list ):
108+ bands = [bands ]
109+
110+ selected_wavelengths = []
111+ for band in bands :
112+ if isinstance (band , (int , np .integer )) or (
113+ isinstance (band , float ) and band < 500
114+ ):
115+ # Treat as band index
116+ selected_wavelengths .append (
117+ dataset .coords ["wavelength" ].values [int (band )]
118+ )
119+ else :
120+ # Treat as wavelength value
121+ selected_wavelengths .append (band )
122+ else :
123+ # Default to first wavelength
124+ selected_wavelengths = [dataset .coords ["wavelength" ].values [0 ]]
104125
105126 lat = dataset .latitude
106127 lon = dataset .longitude
107128
108- # Find valid data points for any band to define spatial mask
109- first_band_data = dataset .sel (band = bands [0 ], method = "nearest" )["toa_radiance" ]
110- overall_valid_mask = ~ np .isnan (first_band_data .data ) & (first_band_data .data > 0 )
129+ # Find valid data points for any wavelength to define spatial mask
130+ first_wavelength_data = dataset .sel (
131+ wavelength = selected_wavelengths [0 ], method = "nearest"
132+ )["toa_radiance" ]
133+ overall_valid_mask = ~ np .isnan (first_wavelength_data .data ) & (
134+ first_wavelength_data .data > 0
135+ )
111136
112137 if not np .any (overall_valid_mask ):
113138 # No valid data, return empty grid
114139 grid_lat = np .linspace (lat .min ().values , lat .max ().values , lat .shape [0 ])
115140 grid_lon = np .linspace (lon .min ().values , lon .max ().values , lon .shape [1 ])
116141 grid_lon_2d , grid_lat_2d = np .meshgrid (grid_lon , grid_lat )
117- gridded_data_dict = {band : np .full_like (grid_lat_2d , np .nan ) for band in bands }
142+ gridded_data_dict = {
143+ wl : np .full_like (grid_lat_2d , np .nan ) for wl in selected_wavelengths
144+ }
118145 else :
119146 # Get valid coordinates for spatial masking
120147 valid_lat = lat .data [overall_valid_mask ]
@@ -148,8 +175,8 @@ def grid_tanager(dataset, bands=None, method="nearest", **kwargs):
148175 )
149176
150177 gridded_data_dict = {}
151- for band in bands :
152- data = dataset .sel (band = band , method = "nearest" )["toa_radiance" ]
178+ for wl in selected_wavelengths :
179+ data = dataset .sel (wavelength = wl , method = "nearest" )["toa_radiance" ]
153180
154181 # Mask nodata values (both NaN and zero values)
155182 data_flat = data .data .flatten ()
@@ -166,19 +193,18 @@ def grid_tanager(dataset, bands=None, method="nearest", **kwargs):
166193 )
167194 # Apply spatial mask to prevent edge interpolation
168195 gridded_data [~ inside_hull ] = np .nan
169- gridded_data_dict [band ] = gridded_data
196+ gridded_data_dict [wl ] = gridded_data
170197
171- wavelengths = dataset . wavelength . values [ bands ]
198+ selected_wavelengths = list ( gridded_data_dict . keys ())
172199 # Create a 3D array with dimensions latitude, longitude, and wavelength
173200 gridded_data_3d = np .dstack (list (gridded_data_dict .values ()))
174201
175202 dataset2 = xr .Dataset (
176- {"toa_radiance" : (("latitude" , "longitude" , "band " ), gridded_data_3d )},
203+ {"toa_radiance" : (("latitude" , "longitude" , "wavelength " ), gridded_data_3d )},
177204 coords = {
178205 "latitude" : ("latitude" , grid_lat ),
179206 "longitude" : ("longitude" , grid_lon ),
180- "band" : ("band" , list (gridded_data_dict .keys ())),
181- "wavelength" : ("band" , wavelengths ),
207+ "wavelength" : ("wavelength" , selected_wavelengths ),
182208 },
183209 ** kwargs ,
184210 )
@@ -188,13 +214,16 @@ def grid_tanager(dataset, bands=None, method="nearest", **kwargs):
188214 return dataset2
189215
190216
191- def tanager_to_image (dataset , bands = None , method = "nearest" , output = None , ** kwargs ):
217+ def tanager_to_image (
218+ dataset , bands = None , wavelengths = None , method = "nearest" , output = None , ** kwargs
219+ ):
192220 """
193221 Converts an Tanager dataset to an image.
194222
195223 Args:
196224 dataset (xarray.Dataset or str): The dataset containing the EMIT data or the file path to the dataset.
197- bands (array-like, optional): The specific bands to select. If None, all bands are selected. Defaults to None.
225+ bands (array-like, optional): The specific band indices to select. Defaults to None.
226+ wavelengths (array-like, optional): The specific wavelength values to select. Takes priority over bands. Defaults to None.
198227 method (str, optional): The method to use for data interpolation. Defaults to "nearest".
199228 output (str, optional): The file path where the image will be saved. If None, the image will be returned as a PIL Image object. Defaults to None.
200229 **kwargs: Additional keyword arguments to be passed to `leafmap.array_to_image`.
@@ -207,7 +236,7 @@ def tanager_to_image(dataset, bands=None, method="nearest", output=None, **kwarg
207236 if isinstance (dataset , str ):
208237 dataset = read_tanager (dataset , bands = bands )
209238
210- grid = grid_tanager (dataset , bands = bands , method = method )
239+ grid = grid_tanager (dataset , bands = bands , wavelengths = wavelengths , method = method )
211240
212241 data = grid ["toa_radiance" ]
213242 data .rio .write_crs ("EPSG:4326" , inplace = True )
0 commit comments