From 9d09ff9658c4fdf958a80253d60bfb1e8cbfa365 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 1 Aug 2023 17:07:58 +0000 Subject: [PATCH 01/30] mvp remove intake from Read --- icepyx/core/read.py | 51 ++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 5a497279a..5860e32dc 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -4,6 +4,7 @@ import numpy as np import xarray as xr +import h5py import icepyx.core.is2cat as is2cat import icepyx.core.is2ref as is2ref @@ -258,7 +259,7 @@ def __init__( catalog=None, out_obj_type=None, # xr.Dataset, ): - + # Note: maybe just don't add default values, so that Python enforces their existence? if data_source is None: raise ValueError("Please provide a data source.") else: @@ -271,10 +272,16 @@ def __init__( ) else: self._prod = is2ref._validate_product(product) - + + # TODO delete? seems like it just validates the pattern + # Does Read accept a directory right now? Why would there be multiple files in the list? + # seems like yes, it does accept a directory + # does it check, then, that all the files have the same version and product? pattern_ck, filelist = Read._check_source_for_pattern( data_source, filename_pattern ) + print('pattern_ck', pattern_ck) + print('filelist', filelist) assert pattern_ck # Note: need to check if this works for subset and non-subset NSIDC files (processed_ prepends the former) self._pattern = filename_pattern @@ -282,7 +289,8 @@ def __init__( # this is a first pass at getting rid of mixed product types and warning the user. # it takes an approach assuming the product name is in the filename, but needs reworking if we let multiple products be loaded # one way to handle this would be bring in the product info during the loading step and fill in product there instead of requiring it from the user - filtered_filelist = [file for file in filelist if self._prod in file] + filtered_filelist = [file for file in filelist if self._prod in Read._get_product_and_version(file)] + print('filtered', filtered_filelist) if len(filtered_filelist) == 0: warnings.warn( "Your filenames do not contain a product identifier (e.g. ATL06). " @@ -665,6 +673,13 @@ def _build_dataset_template(self, file): attrs=dict(data_product=self._prod), ) return is2ds + + def _get_product_and_version(filepath): + # TODO either persist this info or remove 'version', since it isn't necessary right now + with h5py.File(filepath, 'r') as f: + product = f['METADATA']['DatasetIdentification'].attrs['shortName'].decode() + version = f['METADATA']['DatasetIdentification'].attrs['VersionID'].decode() + return product, version def _read_single_grp(self, file, grp_path): """ @@ -684,25 +699,10 @@ def _read_single_grp(self, file, grp_path): Xarray dataset with the specified group. """ - - try: - grpcat = is2cat.build_catalog( - file, self._pattern, self._source_type, grp_paths=grp_path - ) - ds = grpcat[self._source_type].read() - - # NOTE: could also do this with h5py, but then would have to read in each variable in the group separately - except ValueError: - grpcat = is2cat.build_catalog( - file, - self._pattern, - self._source_type, - grp_paths=grp_path, - extra_engine_kwargs={"phony_dims": "access"}, - ) - ds = grpcat[self._source_type].read() - - return ds + # I think this would fail if a group that has too high of a level of nesting + # is given. Consider this. + # TODO: update docstring + return xr.open_dataset(file, group=grp_path) def _build_single_file_dataset(self, file, groups_list): """ @@ -722,8 +722,11 @@ def _build_single_file_dataset(self, file, groups_list): ------- Xarray Dataset """ - - file_product = self._read_single_grp(file, "/").attrs["identifier_product_type"] + # why do we do get the product twice? is it important to us that the user tells us + # correctly their product? Do we trust the metadata or the filename more? + # Also revisit the semantics of this. Not sure if it makes semantic sense for this + # to be a class method + file_product, _ = Read._get_product_and_version(file) assert ( file_product == self._prod ), "Your product specification does not match the product specification within your files." From 24f6a42df3b06bf93e2f16e90434a70aef5d4b1c Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 29 Aug 2023 15:58:03 +0000 Subject: [PATCH 02/30] delete is2cat and references --- icepyx/core/is2cat.py | 178 ------------------------------------------ icepyx/core/read.py | 78 +++++++++++------- 2 files changed, 51 insertions(+), 205 deletions(-) delete mode 100644 icepyx/core/is2cat.py diff --git a/icepyx/core/is2cat.py b/icepyx/core/is2cat.py deleted file mode 100644 index f4e66a7bf..000000000 --- a/icepyx/core/is2cat.py +++ /dev/null @@ -1,178 +0,0 @@ -from intake.catalog import Catalog - -# Need to post on intake's page to see if this would be a useful contribution... -# https://github.com/intake/intake/blob/0.6.4/intake/source/utils.py#L216 -def _pattern_to_glob(pattern): - """ - Adapted from intake.source.utils.path_to_glob to convert a path as pattern into a glob style path - that uses the pattern's indicated number of '?' instead of '*' where an int was specified. - - Returns pattern if pattern is not a string. - - Parameters - ---------- - pattern : str - Path as pattern optionally containing format_strings - - Returns - ------- - glob_path : str - Path with int format strings replaced with the proper number of '?' and '*' otherwise. - - Examples - -------- - >>> _pattern_to_glob('{year}/{month}/{day}.csv') - '*/*/*.csv' - >>> _pattern_to_glob('{year:4}/{month:2}/{day:2}.csv') - '????/??/??.csv' - >>> _pattern_to_glob('data/{year:4}{month:02}{day:02}.csv') - 'data/????????.csv' - >>> _pattern_to_glob('data/*.csv') - 'data/*.csv' - """ - from string import Formatter - - if not isinstance(pattern, str): - return pattern - - fmt = Formatter() - glob_path = "" - # prev_field_name = None - for literal_text, field_name, format_specs, _ in fmt.parse(format_string=pattern): - glob_path += literal_text - if field_name and (glob_path != "*"): - try: - glob_path += "?" * int(format_specs) - except ValueError: - glob_path += "*" - # alternatively, you could use bits=utils._get_parts_of_format_string(resolved_string, literal_texts, format_specs) - # and then use len(bits[i]) to get the length of each format_spec - # print(glob_path) - return glob_path - - -def build_catalog( - data_source, - path_pattern, - source_type, - grp_paths=None, - grp_path_params=None, - extra_engine_kwargs=None, - **kwargs -): - """ - Build a general Intake catalog for reading in ICESat-2 data. - This function is used by the read class object to create catalogs from lists of ICESat-2 variables. - - Parameters - ---------- - data_source : string - A string with a full file path or full directory path to ICESat-2 hdf5 (.h5) format files. - Files within a directory must have a consistent filename pattern that includes the "ATL??" data product name. - Files must all be within a single directory. - - path_pattern : string - String that shows the filename pattern as required for Intake's path_as_pattern argument. - - source_type : string - String to use as the Local Catalog Entry name. - - grp_paths : str, default None - Variable paths to load. - Can include general parameter names, which must be contained within double curly brackets and further - described in `grp_path_params`. - Default list based on data product of provided files. - If multiple data products are included in the files, the default list will be for the product of the first file. - This may result in errors during read-in if all files do not have the same variable paths. - - grp_path_params : [dict], default None - List of dictionaries with a keyword for each parameter name specified in the `grp_paths` string. - Each parameter keyword should contain a dictionary with the acceptable keyword-value pairs for the driver being used. - - **kwargs : - Keyword arguments to be passed through to `intake.catalog.Catalog.from_dict()`. - Keywords needed to override default inputs include: - - `source_args_dict` # highest level source information; keys include: "urlpath", "path_as_pattern", driver-specific ("xarray_kwargs" is default) - - `metadata_dict` - - `source_dict` # individual source entry information (default is supplied by data object; "name", "description", "driver", "args") - - `defaults_dict` # catalog "name", "description", "metadata", "entries", etc. - - Returns - ------- - intake.catalog.Catalog object - - See Also - -------- - read.Read - - """ - from intake.catalog.local import LocalCatalogEntry, UserParameter - import intake_xarray - - import icepyx.core.APIformatting as apifmt - - assert ( - grp_paths - ), "You must enter a variable path or you will not be able to read in any data." - - # generalize this/make it so the [engine] values can be entered as kwargs... - engine_key = "xarray_kwargs" - xarray_kwargs_dict = {"engine": "h5netcdf", "group": grp_paths} - if extra_engine_kwargs: - for key in extra_engine_kwargs.keys(): - xarray_kwargs_dict[key] = extra_engine_kwargs[key] - - source_args_dict = { - "urlpath": data_source, - "path_as_pattern": path_pattern, - engine_key: xarray_kwargs_dict, - } - - metadata_dict = {"version": 1} - - source_dict = { - "name": source_type, - "description": "", - "driver": "intake_xarray.netcdf.NetCDFSource", # NOTE: this must be a string or the catalog cannot be imported after saving - "args": source_args_dict, - } - - if grp_path_params: - source_dict = apifmt.combine_params( - source_dict, - {"parameters": [UserParameter(**params) for params in grp_path_params]}, - ) - - # NOTE: LocalCatalogEntry has some required positional args (name, description, driver) - # I tried doing this generally with *source_dict after the positional args (instead of as part of the if) - # but apparently I don't quite get something about passing dicts with * and ** and couldn't make it work - local_cat_source = { - source_type: LocalCatalogEntry( - name=source_dict.pop("name"), - description=source_dict.pop("description"), - driver=source_dict.pop("driver"), - parameters=source_dict.pop("parameters"), - args=source_dict.pop("args"), - ) - } - - else: - local_cat_source = { - source_type: LocalCatalogEntry( - name=source_dict.pop("name"), - description=source_dict.pop("description"), - driver=source_dict.pop("driver"), - args=source_dict.pop("args"), - ) - } - - defaults_dict = { - "name": "IS2-hdf5-icepyx-intake-catalog", - "description": "an icepyx-generated catalog for creating local ICESat-2 intake entries", - "metadata": metadata_dict, - "entries": local_cat_source, - } - - build_cat_dict = apifmt.combine_params(defaults_dict, kwargs) - - return Catalog.from_dict(**build_cat_dict) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 5860e32dc..c4c10b296 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -6,7 +6,6 @@ import xarray as xr import h5py -import icepyx.core.is2cat as is2cat import icepyx.core.is2ref as is2ref from icepyx.core.variables import Variables as Variables from icepyx.core.variables import list_of_dict_vals @@ -207,6 +206,56 @@ def _run_fast_scandir(dir, fn_glob): return subfolders, files +# Need to post on intake's page to see if this would be a useful contribution... +# https://github.com/intake/intake/blob/0.6.4/intake/source/utils.py#L216 +def _pattern_to_glob(pattern): + """ + Adapted from intake.source.utils.path_to_glob to convert a path as pattern into a glob style path + that uses the pattern's indicated number of '?' instead of '*' where an int was specified. + + Returns pattern if pattern is not a string. + + Parameters + ---------- + pattern : str + Path as pattern optionally containing format_strings + + Returns + ------- + glob_path : str + Path with int format strings replaced with the proper number of '?' and '*' otherwise. + + Examples + -------- + >>> _pattern_to_glob('{year}/{month}/{day}.csv') + '*/*/*.csv' + >>> _pattern_to_glob('{year:4}/{month:2}/{day:2}.csv') + '????/??/??.csv' + >>> _pattern_to_glob('data/{year:4}{month:02}{day:02}.csv') + 'data/????????.csv' + >>> _pattern_to_glob('data/*.csv') + 'data/*.csv' + """ + from string import Formatter + + if not isinstance(pattern, str): + return pattern + + fmt = Formatter() + glob_path = "" + # prev_field_name = None + for literal_text, field_name, format_specs, _ in fmt.parse(format_string=pattern): + glob_path += literal_text + if field_name and (glob_path != "*"): + try: + glob_path += "?" * int(format_specs) + except ValueError: + glob_path += "*" + # alternatively, you could use bits=utils._get_parts_of_format_string(resolved_string, literal_texts, format_specs) + # and then use len(bits[i]) to get the length of each format_spec + # print(glob_path) + return glob_path + # To do: test this class and functions therein class Read: @@ -322,28 +371,6 @@ def __init__( # ---------------------------------------------------------------------- # Properties - @property - def is2catalog(self): - """ - Print a generic ICESat-2 Intake catalog. - This catalog does not specify groups, so it cannot be used to read in data. - - """ - if not hasattr(self, "_is2catalog") and hasattr(self, "_catalog_path"): - from intake import open_catalog - - self._is2catalog = open_catalog(self._catalog_path) - - else: - self._is2catalog = is2cat.build_catalog( - self.data_source, - self._pattern, - self._source_type, - grp_paths="/paths/to/variables", - ) - - return self._is2catalog - # I cut and pasted this directly out of the Query class - going to need to reconcile the _source/file stuff there @property @@ -378,7 +405,7 @@ def _check_source_for_pattern(source, filename_pattern): """ Check that the entered data source contains files that match the input filename_pattern """ - glob_pattern = is2cat._pattern_to_glob(filename_pattern) + glob_pattern = _pattern_to_glob(filename_pattern) if os.path.isdir(source): _, filelist = _run_fast_scandir(source, glob_pattern) @@ -609,9 +636,6 @@ def load(self): All items in the wanted variables list will be loaded from the files into memory. If you do not provide a wanted variables list, a default one will be created for you. - - If you would like to use the Intake catalog you provided to read in a single data variable, - simply call Intake's `read()` function on the is2catalog property (e.g. `reader.is2catalog.read()`). """ # todo: From b13b8473644589445c79144f6e53a21b7447c383 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 20:06:14 +0000 Subject: [PATCH 03/30] remove extra comments --- icepyx/core/read.py | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index c4c10b296..f272a3aa4 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -305,7 +305,6 @@ def __init__( data_source=None, product=None, filename_pattern="ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5", - catalog=None, out_obj_type=None, # xr.Dataset, ): # Note: maybe just don't add default values, so that Python enforces their existence? @@ -322,15 +321,9 @@ def __init__( else: self._prod = is2ref._validate_product(product) - # TODO delete? seems like it just validates the pattern - # Does Read accept a directory right now? Why would there be multiple files in the list? - # seems like yes, it does accept a directory - # does it check, then, that all the files have the same version and product? pattern_ck, filelist = Read._check_source_for_pattern( data_source, filename_pattern ) - print('pattern_ck', pattern_ck) - print('filelist', filelist) assert pattern_ck # Note: need to check if this works for subset and non-subset NSIDC files (processed_ prepends the former) self._pattern = filename_pattern @@ -338,8 +331,7 @@ def __init__( # this is a first pass at getting rid of mixed product types and warning the user. # it takes an approach assuming the product name is in the filename, but needs reworking if we let multiple products be loaded # one way to handle this would be bring in the product info during the loading step and fill in product there instead of requiring it from the user - filtered_filelist = [file for file in filelist if self._prod in Read._get_product_and_version(file)] - print('filtered', filtered_filelist) + filtered_filelist = [file for file in filelist if self._prod in file] if len(filtered_filelist) == 0: warnings.warn( "Your filenames do not contain a product identifier (e.g. ATL06). " @@ -355,11 +347,6 @@ def __init__( self._filelist = filelist # after validation, use the notebook code and code outline to start implementing the rest of the class - if catalog is not None: - assert os.path.isfile( - catalog - ), f"Your catalog path '{catalog}' does not point to a valid file." - self._catalog_path = catalog if out_obj_type is not None: print( @@ -697,17 +684,10 @@ def _build_dataset_template(self, file): attrs=dict(data_product=self._prod), ) return is2ds - - def _get_product_and_version(filepath): - # TODO either persist this info or remove 'version', since it isn't necessary right now - with h5py.File(filepath, 'r') as f: - product = f['METADATA']['DatasetIdentification'].attrs['shortName'].decode() - version = f['METADATA']['DatasetIdentification'].attrs['VersionID'].decode() - return product, version def _read_single_grp(self, file, grp_path): """ - For a given file and variable group path, construct an Intake catalog and use it to read in the data. + For a given file and variable group path, construct an an xarray Dataset. Parameters ---------- @@ -723,10 +703,9 @@ def _read_single_grp(self, file, grp_path): Xarray dataset with the specified group. """ - # I think this would fail if a group that has too high of a level of nesting - # is given. Consider this. - # TODO: update docstring - return xr.open_dataset(file, group=grp_path) + + return xr.open_dataset(file, group=grp_path, engine='h5netcdf', + backend_kwargs={'phony_dims': 'access'}) def _build_single_file_dataset(self, file, groups_list): """ @@ -750,7 +729,7 @@ def _build_single_file_dataset(self, file, groups_list): # correctly their product? Do we trust the metadata or the filename more? # Also revisit the semantics of this. Not sure if it makes semantic sense for this # to be a class method - file_product, _ = Read._get_product_and_version(file) + file_product = self._read_single_grp(file, "/").attrs["identifier_product_type"] assert ( file_product == self._prod ), "Your product specification does not match the product specification within your files." From 0779b8017a98ac3f2e683fddcaaebc0ca413ceac Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 20:23:45 +0000 Subject: [PATCH 04/30] update doc strings --- icepyx/core/read.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index f272a3aa4..d3ca0d82a 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -4,7 +4,6 @@ import numpy as np import xarray as xr -import h5py import icepyx.core.is2ref as is2ref from icepyx.core.variables import Variables as Variables @@ -260,7 +259,7 @@ def _pattern_to_glob(pattern): # To do: test this class and functions therein class Read: """ - Data object to create and use Intake catalogs to read ICESat-2 data into the specified formats. + Data object to read ICESat-2 data into the specified formats. Provides flexiblity for reading nested hdf5 files into common analysis formats. Parameters @@ -279,10 +278,6 @@ class Read: The default describes files downloaded directly from NSIDC (subsetted and non-subsetted) for most products (e.g. ATL06). The ATL11 filename pattern from NSIDC is: 'ATL{product:2}_{rgt:4}{orbitsegment:2}_{cycles:4}_{version:3}_{revision:2}.h5'. - catalog : string, default None - Full path to an Intake catalog for reading in data. - If you still need to create a catalog, leave as default. - out_obj_type : object, default xarray.Dataset The desired format for the data to be read in. Currently, only xarray.Dataset objects (default) are available. @@ -307,7 +302,6 @@ def __init__( filename_pattern="ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5", out_obj_type=None, # xr.Dataset, ): - # Note: maybe just don't add default values, so that Python enforces their existence? if data_source is None: raise ValueError("Please provide a data source.") else: @@ -320,7 +314,6 @@ def __init__( ) else: self._prod = is2ref._validate_product(product) - pattern_ck, filelist = Read._check_source_for_pattern( data_source, filename_pattern ) @@ -725,10 +718,6 @@ def _build_single_file_dataset(self, file, groups_list): ------- Xarray Dataset """ - # why do we do get the product twice? is it important to us that the user tells us - # correctly their product? Do we trust the metadata or the filename more? - # Also revisit the semantics of this. Not sure if it makes semantic sense for this - # to be a class method file_product = self._read_single_grp(file, "/").attrs["identifier_product_type"] assert ( file_product == self._prod From 1cfbf7208a8de80a1539d25e0c536f6831330c25 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 20:24:00 +0000 Subject: [PATCH 05/30] update tests --- icepyx/tests/test_read.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/icepyx/tests/test_read.py b/icepyx/tests/test_read.py index 9748ae992..018435968 100644 --- a/icepyx/tests/test_read.py +++ b/icepyx/tests/test_read.py @@ -63,7 +63,6 @@ def test_validate_source_str_not_a_dir_or_file(): ), sorted( [ - "./icepyx/core/is2cat.py", "./icepyx/core/is2ref.py", "./icepyx/tests/is2class_query.py", ] @@ -73,7 +72,7 @@ def test_validate_source_str_not_a_dir_or_file(): ( "./icepyx/core", "is2*.py", - ([], ["./icepyx/core/is2cat.py", "./icepyx/core/is2ref.py"]), + ([], ["./icepyx/core/is2ref.py"]), ), ( "./icepyx", From de61d87e21ccb4e1feb0e289b83a66ffc1690566 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 20:43:07 +0000 Subject: [PATCH 06/30] update documentation for removing intake --- .../example_notebooks/IS2_data_read-in.ipynb | 2268 +++++++++++++++-- doc/source/user_guide/documentation/read.rst | 1 - 2 files changed, 2052 insertions(+), 217 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index dc9d8ed31..b8697b1d7 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -3,7 +3,9 @@ { "cell_type": "markdown", "id": "552e9ef9", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "# Reading ICESat-2 Data in for Analysis\n", "This notebook ({nb-download}`download `) illustrates the use of icepyx for reading ICESat-2 data files, loading them into a data object.\n", @@ -36,7 +38,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "2b74b672", "metadata": {}, "outputs": [], @@ -47,7 +49,9 @@ { "cell_type": "markdown", "id": "1ffb9a0c", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "---------------------------------\n", "\n", @@ -57,10 +61,18 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "c4390195", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You have 6 files matching the filename pattern to be read in.\n" + ] + } + ], "source": [ "path_root = '/full/path/to/your/data/'\n", "pattern = \"processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"\n", @@ -69,7 +81,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "2f46029d", "metadata": {}, "outputs": [], @@ -79,10 +91,603 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "c0439388", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:              (photon_idx: 29027, spot: 2, gran_idx: 6)\n",
+       "Coordinates:\n",
+       "  * photon_idx           (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n",
+       "  * spot                 (spot) uint8 2 5\n",
+       "  * gran_idx             (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n",
+       "    source_file          (gran_idx) <U72 '../../../../data/ATL06/processed_AT...\n",
+       "    delta_time           (gran_idx, photon_idx) datetime64[ns] 2019-02-22T01:...\n",
+       "Data variables:\n",
+       "    sc_orient            (gran_idx) int8 0 0 0 1 1 1\n",
+       "    cycle_number         (gran_idx) int8 2 2 2 5 5 5\n",
+       "    rgt                  (gran_idx) int16 849 902 910 986 1001 1016\n",
+       "    atlas_sdp_gps_epoch  (gran_idx) datetime64[ns] 2018-01-01T00:00:18 ... 20...\n",
+       "    data_start_utc       (gran_idx) datetime64[ns] 2019-02-22T01:03:44.199777...\n",
+       "    data_end_utc         (gran_idx) datetime64[ns] 2019-02-22T01:07:38.112326...\n",
+       "    h_li                 (spot, gran_idx, photon_idx) float32 nan nan ... nan\n",
+       "    latitude             (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
+       "    longitude            (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
+       "    gt                   (gran_idx, spot) <U4 'gt3r' 'gt1l' ... 'gt1l' 'gt3r'\n",
+       "Attributes:\n",
+       "    data_product:  ATL06\n",
+       "    Description:   The land_ice_height group contains the primary set of deri...\n",
+       "    data_rate:     Data within this group are sparse.  Data values are provid...
" + ], + "text/plain": [ + "\n", + "Dimensions: (photon_idx: 29027, spot: 2, gran_idx: 6)\n", + "Coordinates:\n", + " * photon_idx (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n", + " * spot (spot) uint8 2 5\n", + " * gran_idx (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n", + " source_file (gran_idx) " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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p6cDkJKSwvTp0x0u16GA59ixY7z44os8/PDDJCQkALBq1SoOHjxoVzlvvfUWUVFRLFiwgNatW1OzZk3uuusu6tSpY83zwgsvcPfdd/P222/TvHlzateuTe/evQkNDXWk6kIIIYT7lXB31o0yMjL48ssveeyxx2x2I9+wYQOhoaHUq1ePESNGWD/jAaKjo8nMzKR79+7WtMjISBo3bsyWLVucq9B1Xn/9dT7++GM++eQTm1WW27dvz+7dux0u1+6AZ+PGjTRp0oTt27fz/fffk5qaCsC+ffuYOnWqXWUtX76cVq1aMWDAAEJDQ2nevDmffPKJ9byu6/z000/Uq1ePHj16EBoaSps2bVi2bFm+Zaanp5OcnGxzCCGEEKWKi8bwKKVyfebltIgUZNmyZVy6dInhw4db03r16sXixYv59ddfmTlzJjt37uTOO++0lhcfH4+Pjw+VK1e2KSssLIz4+Hhn/ho2Dh06RMeOHXOlBwUFcenSJYfLtTvgef7553n99ddZu3YtPj4+1vQuXbqwdetWu8r6559/+Oijj6hbty6rV6/mqaeeYsyYMSxatAiAhIQEUlNTefPNN+nZsydr1qzhvvvuo3///rmWm84xY8YMTCaT9YiKirL3EoUQQogyIT4+3uYzz2QyMWPGjEIfN3/+fHr16kVkZKQ17cEHH6R37940btyYe+65h5UrV3L48GF++umnAstSStm0EjkrIiKCo0eP5krfvHkztWvXdrhcu6el79+/n6+++ipXetWqVblw4YJdZem6TqtWrax9cs2bN+fgwYN89NFHDB061LrgYb9+/Rg3bhwAzZo1Y8uWLXz88cc2/Y45pkyZwvjx462/JycnS9AjhBCiVHHF1hKagvDwcA4dOmST7uvrW+DjTpw4wbp16/j+++8LzBcREUGNGjU4cuQIYHmujIwMEhMTbVp5EhISaN++vYNXkdvIkSN59tln+eyzz9A0jdOnT7N161YmTpzIyy+/7HC5drfwVKpUiTNnzuRK37NnDzfddJNdZUVERNCoUSObtIYNG1pnYIWEhODl5VVgnhv5+voSFBRkcwghhBCljgvG8Gialuszr7CAZ8GCBYSGhtK7d+8C8124cIGTJ08SEREBQMuWLfH29rbO7gI4c+YMBw4ccGnAM3nyZO699166dOlCamoqHTt25IknnmDkyJGMHj3a4XLt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vbs1LTIyksaNG7Nlyxan6lPcpIVHCJGLpnnn+bMQwkVctHmoUork5GSbZF9fX3x9fQt+qFKMHz+e22+/ncaNG1vTe/XqxYABA6hRowYxMTG89NJL3HnnnURHR+Pr60t8fDw+Pj5UrlzZprywsDDi4+OdvKDiJQGPEEIIUUbFx8djMpls0qZOncq0adMKfNzo0aPZt28fmzdvtkl/8MEHrT83btyYVq1aUaNGDX766Sf69++fb3llYY89CXiEEEKIEuaqrSXCw8NzzbQqrHXnmWeeYfny5fz2229Uq1atwLwRERHUqFGDI0eOABAeHk5GRgaJiYk2rTwJCQm0b1/ALM9SQMbwCCGEEO7g9MKDlnF3QUFBNkd+AY9SitGjR/P999/z66+/UqtWrUKreOHCBU6ePElERAQALVu2xNvbm7Vr11rznDlzhgMHDpT6gEdaeIQQQoiSplPiu6U//fTTfPXVV/zwww9UrFjROubGZDLh7+9Pamoq06ZN4/777yciIoLjx4/z73//m5CQEO677z5r3scff5wJEyZQpUoVgoODmThxIk2aNLHO2iqtJOARQgghyoGPPvoIgM6dO9ukL1iwgOHDh2M0Gtm/fz+LFi3i0qVLRERE0KVLF7755hsqVqxozT979my8vLwYOHAgaWlp3HXXXSxcuBCjsXTP5HR7wBMXF8dzzz3HypUrSUtLo169esyfP5+WLVuSmZnJiy++yM8//8w///yDyWSia9euvPnmm0RGRrq76kIIIYRDNFwzhsceqpD8/v7+rF69utBy/Pz8eP/993n//fften53c+sYnsTERDp06IC3tzcrV67kzz//ZObMmVSqVAmAK1eusHv3bl566SV2797N999/z+HDh+nbt687qy2EEEI4xyUbh8pmWvZwawvPW2+9RVRUFAsWLLCm1axZ0/qzyWSyGRgF8P7779O6dWtiY2OpXr16SVVVCCGEcB2F87udS7xjF7e28CxfvpxWrVoxYMAAQkNDad68OZ988kmBj0lKSkLTNGsrkBBCCCFEYdwa8Pzzzz989NFH1K1bl9WrV/PUU08xZswYFi1alGf+q1ev8vzzzzNo0CCCgoLyzJOenk5ycrLNIYQQQpQqimsztRw9pIXHLm7t0tJ1nVatWjF9+nQAmjdvzsGDB/noo48YOnSoTd7MzEweeughdF3nww8/zLfM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rb7++us8y1i8eLHy8fHJld61a1c1cuTIYrmWd999V7Vv397anx4TE1Ngl8mWLVsUoHbt2mVXfZQqmdfG3uvJ8Z///EcFBQXle96Vr01xXo873juuvBZ3v2/suZ4c586dU4cOHVJr1qxRHTp0UHfffbfSdT1Xue547xTXteQo6feNKN08uoVn9OjRhc4cqFmzZp7pbdu2BeDo0aNUqVLFmv7nn39y5513MmLEiHy/NRSkRYsWeHt7c+TIEVq0aGHXY115PeHh4Wzfvt0mT2JiIpmZmbm+weYIDw8nIyODxMREm29ECQkJtG/f3o4rKfq1vP7662zbti3XcvGtWrVi8ODBfP755zbpn376Kc2aNaNly5Z21QdK5rWx93pytG3bluTkZM6ePZvn6+PK16a4rsdd7x1XXou73zf2XE+OkJAQQkJCqFevHg0bNiQqKopt27bRrl07m8e4471TXNeSo6TfN6KUc3fEVVr9+OOPClAnTpywph04cECFhoaqSZMmOVzu/v37FaA2btzoimoW2Y3XkzP48vTp09Y8S5YsKdLgy2+++caadvr06WId4HfixAm1f/9+67F69WoFqG+//VadPHnSJm9KSoqqUKFCobN/8lMSr40913O9999/X/n5+amrV6/med4dr41SRb+esvDeKcq1lJX3TX5iY2MVoNavX2+TXhbeOzfK71quV1rfN8I9JOBRlqbcWbNmqT179qh//vlHffPNNyoyMlL17dvXmienKX7w4ME2Ux4TEhKseU6dOqXq16+vtm/frpRS6ujRo+qVV15RO3fuVDExMeqnn35SDRo0UM2bNy/WKY9FuZ6c6bV33XWX2r17t1q3bp2qVq2azfTaG69HKcsUzmrVqql169ap3bt3qzvvvLNEp3AW1GXy6aefKj8/P3Xx4sVc50rLa3OjvK5n+fLlat68eWr//v3q6NGj6pNPPlFBQUFqzJgx+V6PUu5/bfK7nrL03insWsrS+2b79u3q/fffV3v27FHHjx9Xv/76q7r99ttVnTp1cgUApf29U5RrKcvvG1EyJOBRSkVHR6s2bdook8mk/Pz8VP369dXUqVPV5cuXrXny62uuUaOGNU/ODTLnG0dsbKzq2LGjCg4OVj4+PqpOnTpqzJgx6sKFC26/HqUs32h79+6t/P39VXBwsBo9erTNjfDG61FKqbS0NDV69GgVHBys/P39VZ8+fVRsbGyxXs/1Cgp42rVrpwYNGlTg49z92uRXr+uvZ+XKlapZs2aqQoUKKiAgQDVu3FjNmTNHZWZm5ns9Srn/tbm+XtdfT1l67xR2LUqVnffNvn37VJcuXVRwcLDy9fVVNWvWVE899ZQ6depUrryl/b1TlGspy+8bUTJkt3QhhBBCeDxZh0cIIYQQHk8CHiGEEEJ4PAl4hBBCCOHxJOARQgghhMeTgEcIIYQQHk8CHiGEEEJ4PAl4hBBCCOHxJOARQgghhMeTgEeIQhw/fhxN09i7d2+xlK9pGsuWLXP48Rs2bEDTNDRN49577y0wb+fOnRk7dqzDzyUKlvM6VKpUyd1VEULcQAIeUaoNHz680A/x4hYVFcWZM2do3LgxcC3AuHTpklvrdaNDhw6xcOFCd1ejXMjv3+WZM2eYM2dOiddHCFE4CXiEKITRaCQ8PBwvLy93V6VAoaGhpaJlITMz091VcJvw8HBMJpO7qyGEyIMEPKJM27hxI61bt8bX15eIiAief/55srKyrOc7d+7MmDFjmDx5MsHBwYSHhzNt2jSbMv7++29uv/12/Pz8aNSoEevWrbPpZrq+S+v48eN06dIFgMqVK6NpGsOHDwegZs2aub7dN2vWzOb5jhw5QseOHa3PtXbt2lzXFBcXx4MPPkjlypWpUqUK/fr14/jx43b/bS5fvszQoUOpUKECERERzJw5M1eejIwMJk+ezE033URgYCBt2rRhw4YNNnk++eQToqKiCAgI4L777mPWrFk2gdW0adNo1qwZn332GbVr18bX1xelFElJSTz55JOEhoYSFBTEnXfeyR9//GFT9o8//kjLli3x8/Ojdu3avPLKKzav37Rp06hevTq+vr5ERkYyZsyYIl17Ydd14cIFHn74YapVq0ZAQABNmjTh66+/tinj22+/pUmTJvj7+1OlShW6du3K5cuXmTZtGp9//jk//PCDtQvrxr+ZEKL0Kd1fWYUoQFxcHHfffTfDhw9n0aJF/P3334wYMQI/Pz+bIOPzzz9n/PjxbN++na1btzJ8+HA6dOhAt27d0HWde++9l+rVq7N9+3ZSUlKYMGFCvs8ZFRXFd999x/3338+hQ4cICgrC39+/SPXVdZ3+/fsTEhLCtm3bSE5OzjWe5sqVK3Tp0oU77riD3377DS8vL15//XV69uzJvn378PHxKfLfZ9KkSaxfv56lS5cSHh7Ov//9b6Kjo2nWrJk1z6OPPsrx48dZsmQJkZGRLF26lJ49e7J//37q1q3L77//zlNPPcVbb71F3759WbduHS+99FKu5zp69Cj//e9/+e677zAajQD07t2b4OBgfv75Z0wmE3PnzuWuu+7i8OHDBAcHs3r1ah555BHee+897rjjDo4dO8aTTz4JwNSpU/n222+ZPXs2S5Ys4ZZbbiE+Pj5XwJSfwq7r6tWrtGzZkueee46goCB++uknhgwZQu3atWnTpg1nzpzh4Ycf5u233+a+++4jJSWFTZs2oZRi4sSJ/PXXXyQnJ7NgwQIAgoODi/y6CCHcxL2btQtRsGHDhql+/frlee7f//63ql+/vtJ13Zr2f//3f6pChQrKbDYrpZTq1KmTuv32220ed9ttt6nnnntOKaXUypUrlZeXlzpz5oz1/Nq1axWgli5dqpRSKiYmRgFqz549Siml1q9frwCVmJhoU26NGjXU7NmzbdKaNm2qpk6dqpRSavXq1cpoNKqTJ09az69cudLmuebPn5/rmtLT05W/v79avXp1nn+HvOqTkpKifHx81JIlS6xpFy5cUP7+/urZZ59VSil19OhRpWmaiouLsynvrrvuUlOmTFFKKfXggw+q3r1725wfPHiwMplM1t+nTp2qvL29VUJCgjXtl19+UUFBQerq1as2j61Tp46aO3euUkqpO+64Q02fPt3m/BdffKEiIiKUUkrNnDlT1atXT2VkZOR53fkpynXl5e6771YTJkxQSikVHR2tAHX8+PE88xb073LBggU2fx8hROkgLTyizPrrr79o164dmqZZ0zp06EBqaiqnTp2ievXqANx66602j4uIiCAhIQGwDPSNiooiPDzcer5169bFVt/q1atTrVo1a1q7du1s8kRHR3P06FEqVqxok3716lWOHTtW5Oc6duwYGRkZNuUHBwdTv3596++7d+9GKUW9evVsHpuenk6VKlUAy9/nvvvusznfunVrVqxYYZNWo0YNqlatanMdqamp1nJypKWlWa8jOjqanTt38sYbb1jPm81mrl69ypUrVxgwYABz5syhdu3a9OzZk7vvvpt77rmn0LFURbkus9nMm2++yTfffENcXBzp6emkp6cTGBgIQNOmTbnrrrto0qQJPXr0oHv37jzwwANUrly5wOcWQpReEvCI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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "ds.plot.scatter(x=\"longitude\", y=\"latitude\", hue=\"h_li\", vmin=-100, vmax=2000)" ] @@ -101,7 +727,9 @@ { "cell_type": "markdown", "id": "b8875936", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "---------------------------------------\n", "## Key steps for loading (reading) ICESat-2 data\n", @@ -119,7 +747,9 @@ { "cell_type": "markdown", "id": "9bf6d38c", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "### Step 0: Get some data if you haven't already\n", "Here are a few lines of code to get you set up with a few data files if you don't already have some on your local system." @@ -127,7 +757,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "63da2b3c", "metadata": {}, "outputs": [], @@ -138,10 +768,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "e6f7c047", "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'Query' object has no attribute '_session'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mregion_a\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdownload_granules\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpath_root\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/envs/general/lib/python3.11/site-packages/icepyx/core/query.py:1129\u001b[0m, in \u001b[0;36mQuery.download_granules\u001b[0;34m(self, path, verbose, subset, restart, **kwargs)\u001b[0m\n\u001b[1;32m 1124\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 1125\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[1;32m 1126\u001b[0m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124morderIDs\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 1127\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39morderIDs) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m 1128\u001b[0m ):\n\u001b[0;32m-> 1129\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43morder_granules\u001b[49m\u001b[43m(\u001b[49m\u001b[43mverbose\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mverbose\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msubset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msubset\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1131\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39mdownload(verbose, path, session\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_session, restart\u001b[38;5;241m=\u001b[39mrestart)\n", + "File \u001b[0;32m~/envs/general/lib/python3.11/site-packages/icepyx/core/query.py:1065\u001b[0m, in \u001b[0;36mQuery.order_granules\u001b[0;34m(self, verbose, subset, email, **kwargs)\u001b[0m\n\u001b[1;32m 1048\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39mplace_order(\n\u001b[1;32m 1049\u001b[0m tempCMRparams,\n\u001b[1;32m 1050\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreqparams,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1055\u001b[0m geom_filepath\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_spatial\u001b[38;5;241m.\u001b[39m_geom_file,\n\u001b[1;32m 1056\u001b[0m )\n\u001b[1;32m 1058\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 1059\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39mplace_order(\n\u001b[1;32m 1060\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mCMRparams,\n\u001b[1;32m 1061\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreqparams,\n\u001b[1;32m 1062\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msubsetparams(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs),\n\u001b[1;32m 1063\u001b[0m verbose,\n\u001b[1;32m 1064\u001b[0m subset,\n\u001b[0;32m-> 1065\u001b[0m session\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_session\u001b[49m,\n\u001b[1;32m 1066\u001b[0m geom_filepath\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_spatial\u001b[38;5;241m.\u001b[39m_geom_file,\n\u001b[1;32m 1067\u001b[0m )\n", + "\u001b[0;31mAttributeError\u001b[0m: 'Query' object has no attribute '_session'" + ] + } + ], "source": [ "region_a.download_granules(path=path_root)" ] @@ -182,7 +826,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "9cde6679", "metadata": {}, "outputs": [], @@ -192,7 +836,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "8b6edf0c", "metadata": {}, "outputs": [], @@ -202,7 +846,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "id": "e683ebf7", "metadata": {}, "outputs": [], @@ -213,7 +857,9 @@ { "cell_type": "markdown", "id": "92743496", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "### Step 2: Create a filename pattern for your data files\n", "\n", @@ -227,7 +873,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "id": "7318abd0", "metadata": {}, "outputs": [], @@ -238,7 +884,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "id": "f43e8664", "metadata": {}, "outputs": [], @@ -248,7 +894,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "id": "992a77fb", "metadata": {}, "outputs": [], @@ -258,7 +904,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "id": "6aec1a70", "metadata": {}, "outputs": [], @@ -269,7 +915,9 @@ { "cell_type": "markdown", "id": "4275b04c", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "### Step 3: Create an icepyx read object\n", "\n", @@ -277,29 +925,52 @@ "- `path` = a string with the full file path or full directory path to your hdf5 (.h5) format files.\n", "- `product` = the data product you're working with, also known as the \"short name\".\n", "\n", - "The `Read` object also accepts two optional keyword inputs:\n", - "- `pattern` = a formatted string indicating the filename pattern required for Intake's path_as_pattern argument.\n", - "- `catalog` = a string with the full path to an Intake catalog, for users who wish to use their own catalog (note this may have unintended consequenses if multiple granules are being combined)." + "The `Read` object also accepts the optional keyword input:\n", + "- `pattern` = a formatted string indicating the filename pattern required for Intake's path_as_pattern argument." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "id": "39bd7eb8", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You have 6 files matching the filename pattern to be read in.\n" + ] + } + ], "source": [ "reader = ipx.Read(data_source=path_root, product=\"ATL06\", filename_pattern=pattern) # or ipx.Read(filepath, \"ATLXX\") if your filenames match the default pattern" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "id": "6c9ebc4a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['../../../../data/ATL06/processed_ATL06_20190226005526_09100205_006_02.h5',\n", + " '../../../../data/ATL06/processed_ATL06_20191201105502_10010505_006_01.h5',\n", + " '../../../../data/ATL06/processed_ATL06_20190225121032_09020203_006_02.h5',\n", + " '../../../../data/ATL06/processed_ATL06_20190222010344_08490205_006_02.h5',\n", + " '../../../../data/ATL06/processed_ATL06_20191130112041_09860505_006_01.h5',\n", + " '../../../../data/ATL06/processed_ATL06_20191202102922_10160505_006_01.h5']" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "reader._filelist" ] @@ -307,7 +978,9 @@ { "cell_type": "markdown", "id": "da8d8024", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "### Step 4: Specify variables to be read in\n", "\n", @@ -320,12 +993,616 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "18f65f67", "metadata": { "scrolled": true }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "['ancillary_data/atlas_sdp_gps_epoch',\n", + " 'ancillary_data/control',\n", + " 'ancillary_data/data_end_utc',\n", + " 'ancillary_data/data_start_utc',\n", + " 'ancillary_data/end_cycle',\n", + " 'ancillary_data/end_delta_time',\n", + " 'ancillary_data/end_geoseg',\n", + " 'ancillary_data/end_gpssow',\n", + " 'ancillary_data/end_gpsweek',\n", + " 'ancillary_data/end_orbit',\n", + " 'ancillary_data/end_region',\n", + " 'ancillary_data/end_rgt',\n", + " 'ancillary_data/granule_end_utc',\n", + " 'ancillary_data/granule_start_utc',\n", + " 'ancillary_data/land_ice/dt_hist',\n", + " 'ancillary_data/land_ice/fit_maxiter',\n", + " 'ancillary_data/land_ice/fpb_maxiter',\n", + " 'ancillary_data/land_ice/max_res_ids',\n", + " 'ancillary_data/land_ice/min_dist',\n", + " 'ancillary_data/land_ice/min_gain_th',\n", + " 'ancillary_data/land_ice/min_n_pe',\n", + " 'ancillary_data/land_ice/min_n_sel',\n", + " 'ancillary_data/land_ice/min_signal_conf',\n", + " 'ancillary_data/land_ice/n_hist',\n", + " 'ancillary_data/land_ice/n_sigmas',\n", + " 'ancillary_data/land_ice/nhist_bins',\n", + " 'ancillary_data/land_ice/proc_interval',\n", + " 'ancillary_data/land_ice/qs_lim_bsc',\n", + " 'ancillary_data/land_ice/qs_lim_hrs',\n", + " 'ancillary_data/land_ice/qs_lim_hsigma',\n", + " 'ancillary_data/land_ice/qs_lim_msw',\n", + " 'ancillary_data/land_ice/qs_lim_snr',\n", + " 'ancillary_data/land_ice/qs_lim_sss',\n", + " 'ancillary_data/land_ice/rbin_width',\n", + " 'ancillary_data/land_ice/sigma_beam',\n", + " 'ancillary_data/land_ice/sigma_tx',\n", + " 'ancillary_data/land_ice/t_dead',\n", + " 'ancillary_data/land_ice/txp_maxiter',\n", + " 'ancillary_data/qa_at_interval',\n", + " 'ancillary_data/release',\n", + " 'ancillary_data/start_cycle',\n", + " 'ancillary_data/start_delta_time',\n", + " 'ancillary_data/start_geoseg',\n", + " 'ancillary_data/start_gpssow',\n", + " 'ancillary_data/start_gpsweek',\n", + " 'ancillary_data/start_orbit',\n", + " 'ancillary_data/start_region',\n", + " 'ancillary_data/start_rgt',\n", + " 'ancillary_data/version',\n", + " 'gt1l/land_ice_segments/atl06_quality_summary',\n", + " 'gt1l/land_ice_segments/bias_correction/fpb_mean_corr',\n", + " 'gt1l/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", + " 'gt1l/land_ice_segments/bias_correction/fpb_med_corr',\n", + " 'gt1l/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", + " 'gt1l/land_ice_segments/bias_correction/fpb_n_corr',\n", + " 'gt1l/land_ice_segments/bias_correction/med_r_fit',\n", + " 'gt1l/land_ice_segments/bias_correction/tx_mean_corr',\n", + " 'gt1l/land_ice_segments/bias_correction/tx_med_corr',\n", + " 'gt1l/land_ice_segments/delta_time',\n", + " 'gt1l/land_ice_segments/dem/dem_flag',\n", + " 'gt1l/land_ice_segments/dem/dem_h',\n", + " 'gt1l/land_ice_segments/dem/geoid_free2mean',\n", + " 'gt1l/land_ice_segments/dem/geoid_h',\n", + " 'gt1l/land_ice_segments/fit_statistics/dh_fit_dx',\n", + " 'gt1l/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", + " 'gt1l/land_ice_segments/fit_statistics/dh_fit_dy',\n", + " 'gt1l/land_ice_segments/fit_statistics/h_expected_rms',\n", + " 'gt1l/land_ice_segments/fit_statistics/h_mean',\n", + " 'gt1l/land_ice_segments/fit_statistics/h_rms_misfit',\n", + " 'gt1l/land_ice_segments/fit_statistics/h_robust_sprd',\n", + " 'gt1l/land_ice_segments/fit_statistics/n_fit_photons',\n", + " 'gt1l/land_ice_segments/fit_statistics/n_seg_pulses',\n", + " 'gt1l/land_ice_segments/fit_statistics/sigma_h_mean',\n", + " 'gt1l/land_ice_segments/fit_statistics/signal_selection_source',\n", + " 'gt1l/land_ice_segments/fit_statistics/signal_selection_source_status',\n", + " 'gt1l/land_ice_segments/fit_statistics/snr',\n", + " 'gt1l/land_ice_segments/fit_statistics/snr_significance',\n", + " 'gt1l/land_ice_segments/fit_statistics/w_surface_window_final',\n", + " 'gt1l/land_ice_segments/geophysical/bckgrd',\n", + " 'gt1l/land_ice_segments/geophysical/bsnow_conf',\n", + " 'gt1l/land_ice_segments/geophysical/bsnow_h',\n", + " 'gt1l/land_ice_segments/geophysical/bsnow_od',\n", + " 'gt1l/land_ice_segments/geophysical/cloud_flg_asr',\n", + " 'gt1l/land_ice_segments/geophysical/cloud_flg_atm',\n", + " 'gt1l/land_ice_segments/geophysical/dac',\n", + " 'gt1l/land_ice_segments/geophysical/e_bckgrd',\n", + " 'gt1l/land_ice_segments/geophysical/layer_flag',\n", + " 'gt1l/land_ice_segments/geophysical/msw_flag',\n", + " 'gt1l/land_ice_segments/geophysical/neutat_delay_total',\n", + " 'gt1l/land_ice_segments/geophysical/r_eff',\n", + " 'gt1l/land_ice_segments/geophysical/solar_azimuth',\n", + " 'gt1l/land_ice_segments/geophysical/solar_elevation',\n", + " 'gt1l/land_ice_segments/geophysical/tide_earth',\n", + " 'gt1l/land_ice_segments/geophysical/tide_earth_free2mean',\n", + " 'gt1l/land_ice_segments/geophysical/tide_equilibrium',\n", + " 'gt1l/land_ice_segments/geophysical/tide_load',\n", + " 'gt1l/land_ice_segments/geophysical/tide_ocean',\n", + " 'gt1l/land_ice_segments/geophysical/tide_pole',\n", + " 'gt1l/land_ice_segments/ground_track/ref_azimuth',\n", + " 'gt1l/land_ice_segments/ground_track/ref_coelv',\n", + " 'gt1l/land_ice_segments/ground_track/seg_azimuth',\n", + " 'gt1l/land_ice_segments/ground_track/sigma_geo_at',\n", + " 'gt1l/land_ice_segments/ground_track/sigma_geo_r',\n", + " 'gt1l/land_ice_segments/ground_track/sigma_geo_xt',\n", + " 'gt1l/land_ice_segments/ground_track/x_atc',\n", + " 'gt1l/land_ice_segments/ground_track/y_atc',\n", + " 'gt1l/land_ice_segments/h_li',\n", + " 'gt1l/land_ice_segments/h_li_sigma',\n", + " 'gt1l/land_ice_segments/latitude',\n", + " 'gt1l/land_ice_segments/longitude',\n", + " 'gt1l/land_ice_segments/segment_id',\n", + " 'gt1l/land_ice_segments/sigma_geo_h',\n", + " 'gt1l/residual_histogram/bckgrd_per_m',\n", + " 'gt1l/residual_histogram/bin_top_h',\n", + " 'gt1l/residual_histogram/count',\n", + " 'gt1l/residual_histogram/delta_time',\n", + " 'gt1l/residual_histogram/ds_segment_id',\n", + " 'gt1l/residual_histogram/lat_mean',\n", + " 'gt1l/residual_histogram/lon_mean',\n", + " 'gt1l/residual_histogram/pulse_count',\n", + " 'gt1l/residual_histogram/segment_id_list',\n", + " 'gt1l/residual_histogram/x_atc_mean',\n", + " 'gt1l/segment_quality/delta_time',\n", + " 'gt1l/segment_quality/record_number',\n", + " 'gt1l/segment_quality/reference_pt_lat',\n", + " 'gt1l/segment_quality/reference_pt_lon',\n", + " 'gt1l/segment_quality/segment_id',\n", + " 'gt1l/segment_quality/signal_selection_source',\n", + " 'gt1l/segment_quality/signal_selection_status/signal_selection_status_all',\n", + " 'gt1l/segment_quality/signal_selection_status/signal_selection_status_backup',\n", + " 'gt1l/segment_quality/signal_selection_status/signal_selection_status_confident',\n", + " 'gt1r/land_ice_segments/atl06_quality_summary',\n", + " 'gt1r/land_ice_segments/bias_correction/fpb_mean_corr',\n", + " 'gt1r/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", + " 'gt1r/land_ice_segments/bias_correction/fpb_med_corr',\n", + " 'gt1r/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", + " 'gt1r/land_ice_segments/bias_correction/fpb_n_corr',\n", + " 'gt1r/land_ice_segments/bias_correction/med_r_fit',\n", + " 'gt1r/land_ice_segments/bias_correction/tx_mean_corr',\n", + " 'gt1r/land_ice_segments/bias_correction/tx_med_corr',\n", + " 'gt1r/land_ice_segments/delta_time',\n", + " 'gt1r/land_ice_segments/dem/dem_flag',\n", + " 'gt1r/land_ice_segments/dem/dem_h',\n", + " 'gt1r/land_ice_segments/dem/geoid_free2mean',\n", + " 'gt1r/land_ice_segments/dem/geoid_h',\n", + " 'gt1r/land_ice_segments/fit_statistics/dh_fit_dx',\n", + " 'gt1r/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", + " 'gt1r/land_ice_segments/fit_statistics/dh_fit_dy',\n", + " 'gt1r/land_ice_segments/fit_statistics/h_expected_rms',\n", + " 'gt1r/land_ice_segments/fit_statistics/h_mean',\n", + " 'gt1r/land_ice_segments/fit_statistics/h_rms_misfit',\n", + " 'gt1r/land_ice_segments/fit_statistics/h_robust_sprd',\n", + " 'gt1r/land_ice_segments/fit_statistics/n_fit_photons',\n", + " 'gt1r/land_ice_segments/fit_statistics/n_seg_pulses',\n", + " 'gt1r/land_ice_segments/fit_statistics/sigma_h_mean',\n", + " 'gt1r/land_ice_segments/fit_statistics/signal_selection_source',\n", + " 'gt1r/land_ice_segments/fit_statistics/signal_selection_source_status',\n", + " 'gt1r/land_ice_segments/fit_statistics/snr',\n", + " 'gt1r/land_ice_segments/fit_statistics/snr_significance',\n", + " 'gt1r/land_ice_segments/fit_statistics/w_surface_window_final',\n", + " 'gt1r/land_ice_segments/geophysical/bckgrd',\n", + " 'gt1r/land_ice_segments/geophysical/bsnow_conf',\n", + " 'gt1r/land_ice_segments/geophysical/bsnow_h',\n", + " 'gt1r/land_ice_segments/geophysical/bsnow_od',\n", + " 'gt1r/land_ice_segments/geophysical/cloud_flg_asr',\n", + " 'gt1r/land_ice_segments/geophysical/cloud_flg_atm',\n", + " 'gt1r/land_ice_segments/geophysical/dac',\n", + " 'gt1r/land_ice_segments/geophysical/e_bckgrd',\n", + " 'gt1r/land_ice_segments/geophysical/layer_flag',\n", + " 'gt1r/land_ice_segments/geophysical/msw_flag',\n", + " 'gt1r/land_ice_segments/geophysical/neutat_delay_total',\n", + " 'gt1r/land_ice_segments/geophysical/r_eff',\n", + " 'gt1r/land_ice_segments/geophysical/solar_azimuth',\n", + " 'gt1r/land_ice_segments/geophysical/solar_elevation',\n", + " 'gt1r/land_ice_segments/geophysical/tide_earth',\n", + " 'gt1r/land_ice_segments/geophysical/tide_earth_free2mean',\n", + " 'gt1r/land_ice_segments/geophysical/tide_equilibrium',\n", + " 'gt1r/land_ice_segments/geophysical/tide_load',\n", + " 'gt1r/land_ice_segments/geophysical/tide_ocean',\n", + " 'gt1r/land_ice_segments/geophysical/tide_pole',\n", + " 'gt1r/land_ice_segments/ground_track/ref_azimuth',\n", + " 'gt1r/land_ice_segments/ground_track/ref_coelv',\n", + " 'gt1r/land_ice_segments/ground_track/seg_azimuth',\n", + " 'gt1r/land_ice_segments/ground_track/sigma_geo_at',\n", + " 'gt1r/land_ice_segments/ground_track/sigma_geo_r',\n", + " 'gt1r/land_ice_segments/ground_track/sigma_geo_xt',\n", + " 'gt1r/land_ice_segments/ground_track/x_atc',\n", + " 'gt1r/land_ice_segments/ground_track/y_atc',\n", + " 'gt1r/land_ice_segments/h_li',\n", + " 'gt1r/land_ice_segments/h_li_sigma',\n", + " 'gt1r/land_ice_segments/latitude',\n", + " 'gt1r/land_ice_segments/longitude',\n", + " 'gt1r/land_ice_segments/segment_id',\n", + " 'gt1r/land_ice_segments/sigma_geo_h',\n", + " 'gt1r/residual_histogram/bckgrd_per_m',\n", + " 'gt1r/residual_histogram/bin_top_h',\n", + " 'gt1r/residual_histogram/count',\n", + " 'gt1r/residual_histogram/delta_time',\n", + " 'gt1r/residual_histogram/ds_segment_id',\n", + " 'gt1r/residual_histogram/lat_mean',\n", + " 'gt1r/residual_histogram/lon_mean',\n", + " 'gt1r/residual_histogram/pulse_count',\n", + " 'gt1r/residual_histogram/segment_id_list',\n", + " 'gt1r/residual_histogram/x_atc_mean',\n", + " 'gt1r/segment_quality/delta_time',\n", + " 'gt1r/segment_quality/record_number',\n", + " 'gt1r/segment_quality/reference_pt_lat',\n", + " 'gt1r/segment_quality/reference_pt_lon',\n", + " 'gt1r/segment_quality/segment_id',\n", + " 'gt1r/segment_quality/signal_selection_source',\n", + " 'gt1r/segment_quality/signal_selection_status/signal_selection_status_all',\n", + " 'gt1r/segment_quality/signal_selection_status/signal_selection_status_backup',\n", + " 'gt1r/segment_quality/signal_selection_status/signal_selection_status_confident',\n", + " 'gt2l/land_ice_segments/atl06_quality_summary',\n", + " 'gt2l/land_ice_segments/bias_correction/fpb_mean_corr',\n", + " 'gt2l/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", + " 'gt2l/land_ice_segments/bias_correction/fpb_med_corr',\n", + " 'gt2l/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", + " 'gt2l/land_ice_segments/bias_correction/fpb_n_corr',\n", + " 'gt2l/land_ice_segments/bias_correction/med_r_fit',\n", + " 'gt2l/land_ice_segments/bias_correction/tx_mean_corr',\n", + " 'gt2l/land_ice_segments/bias_correction/tx_med_corr',\n", + " 'gt2l/land_ice_segments/delta_time',\n", + " 'gt2l/land_ice_segments/dem/dem_flag',\n", + " 'gt2l/land_ice_segments/dem/dem_h',\n", + " 'gt2l/land_ice_segments/dem/geoid_free2mean',\n", + " 'gt2l/land_ice_segments/dem/geoid_h',\n", + " 'gt2l/land_ice_segments/fit_statistics/dh_fit_dx',\n", + " 'gt2l/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", + " 'gt2l/land_ice_segments/fit_statistics/dh_fit_dy',\n", + " 'gt2l/land_ice_segments/fit_statistics/h_expected_rms',\n", + " 'gt2l/land_ice_segments/fit_statistics/h_mean',\n", + " 'gt2l/land_ice_segments/fit_statistics/h_rms_misfit',\n", + " 'gt2l/land_ice_segments/fit_statistics/h_robust_sprd',\n", + " 'gt2l/land_ice_segments/fit_statistics/n_fit_photons',\n", + " 'gt2l/land_ice_segments/fit_statistics/n_seg_pulses',\n", + " 'gt2l/land_ice_segments/fit_statistics/sigma_h_mean',\n", + " 'gt2l/land_ice_segments/fit_statistics/signal_selection_source',\n", + " 'gt2l/land_ice_segments/fit_statistics/signal_selection_source_status',\n", + " 'gt2l/land_ice_segments/fit_statistics/snr',\n", + " 'gt2l/land_ice_segments/fit_statistics/snr_significance',\n", + " 'gt2l/land_ice_segments/fit_statistics/w_surface_window_final',\n", + " 'gt2l/land_ice_segments/geophysical/bckgrd',\n", + " 'gt2l/land_ice_segments/geophysical/bsnow_conf',\n", + " 'gt2l/land_ice_segments/geophysical/bsnow_h',\n", + " 'gt2l/land_ice_segments/geophysical/bsnow_od',\n", + " 'gt2l/land_ice_segments/geophysical/cloud_flg_asr',\n", + " 'gt2l/land_ice_segments/geophysical/cloud_flg_atm',\n", + " 'gt2l/land_ice_segments/geophysical/dac',\n", + " 'gt2l/land_ice_segments/geophysical/e_bckgrd',\n", + " 'gt2l/land_ice_segments/geophysical/layer_flag',\n", + " 'gt2l/land_ice_segments/geophysical/msw_flag',\n", + " 'gt2l/land_ice_segments/geophysical/neutat_delay_total',\n", + " 'gt2l/land_ice_segments/geophysical/r_eff',\n", + " 'gt2l/land_ice_segments/geophysical/solar_azimuth',\n", + " 'gt2l/land_ice_segments/geophysical/solar_elevation',\n", + " 'gt2l/land_ice_segments/geophysical/tide_earth',\n", + " 'gt2l/land_ice_segments/geophysical/tide_earth_free2mean',\n", + " 'gt2l/land_ice_segments/geophysical/tide_equilibrium',\n", + " 'gt2l/land_ice_segments/geophysical/tide_load',\n", + " 'gt2l/land_ice_segments/geophysical/tide_ocean',\n", + " 'gt2l/land_ice_segments/geophysical/tide_pole',\n", + " 'gt2l/land_ice_segments/ground_track/ref_azimuth',\n", + " 'gt2l/land_ice_segments/ground_track/ref_coelv',\n", + " 'gt2l/land_ice_segments/ground_track/seg_azimuth',\n", + " 'gt2l/land_ice_segments/ground_track/sigma_geo_at',\n", + " 'gt2l/land_ice_segments/ground_track/sigma_geo_r',\n", + " 'gt2l/land_ice_segments/ground_track/sigma_geo_xt',\n", + " 'gt2l/land_ice_segments/ground_track/x_atc',\n", + " 'gt2l/land_ice_segments/ground_track/y_atc',\n", + " 'gt2l/land_ice_segments/h_li',\n", + " 'gt2l/land_ice_segments/h_li_sigma',\n", + " 'gt2l/land_ice_segments/latitude',\n", + " 'gt2l/land_ice_segments/longitude',\n", + " 'gt2l/land_ice_segments/segment_id',\n", + " 'gt2l/land_ice_segments/sigma_geo_h',\n", + " 'gt2l/residual_histogram/bckgrd_per_m',\n", + " 'gt2l/residual_histogram/bin_top_h',\n", + " 'gt2l/residual_histogram/count',\n", + " 'gt2l/residual_histogram/delta_time',\n", + " 'gt2l/residual_histogram/ds_segment_id',\n", + " 'gt2l/residual_histogram/lat_mean',\n", + " 'gt2l/residual_histogram/lon_mean',\n", + " 'gt2l/residual_histogram/pulse_count',\n", + " 'gt2l/residual_histogram/segment_id_list',\n", + " 'gt2l/residual_histogram/x_atc_mean',\n", + " 'gt2l/segment_quality/delta_time',\n", + " 'gt2l/segment_quality/record_number',\n", + " 'gt2l/segment_quality/reference_pt_lat',\n", + " 'gt2l/segment_quality/reference_pt_lon',\n", + " 'gt2l/segment_quality/segment_id',\n", + " 'gt2l/segment_quality/signal_selection_source',\n", + " 'gt2l/segment_quality/signal_selection_status/signal_selection_status_all',\n", + " 'gt2l/segment_quality/signal_selection_status/signal_selection_status_backup',\n", + " 'gt2l/segment_quality/signal_selection_status/signal_selection_status_confident',\n", + " 'gt2r/land_ice_segments/atl06_quality_summary',\n", + " 'gt2r/land_ice_segments/bias_correction/fpb_mean_corr',\n", + " 'gt2r/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", + " 'gt2r/land_ice_segments/bias_correction/fpb_med_corr',\n", + " 'gt2r/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", + " 'gt2r/land_ice_segments/bias_correction/fpb_n_corr',\n", + " 'gt2r/land_ice_segments/bias_correction/med_r_fit',\n", + " 'gt2r/land_ice_segments/bias_correction/tx_mean_corr',\n", + " 'gt2r/land_ice_segments/bias_correction/tx_med_corr',\n", + " 'gt2r/land_ice_segments/delta_time',\n", + " 'gt2r/land_ice_segments/dem/dem_flag',\n", + " 'gt2r/land_ice_segments/dem/dem_h',\n", + " 'gt2r/land_ice_segments/dem/geoid_free2mean',\n", + " 'gt2r/land_ice_segments/dem/geoid_h',\n", + " 'gt2r/land_ice_segments/fit_statistics/dh_fit_dx',\n", + " 'gt2r/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", + " 'gt2r/land_ice_segments/fit_statistics/dh_fit_dy',\n", + " 'gt2r/land_ice_segments/fit_statistics/h_expected_rms',\n", + " 'gt2r/land_ice_segments/fit_statistics/h_mean',\n", + " 'gt2r/land_ice_segments/fit_statistics/h_rms_misfit',\n", + " 'gt2r/land_ice_segments/fit_statistics/h_robust_sprd',\n", + " 'gt2r/land_ice_segments/fit_statistics/n_fit_photons',\n", + " 'gt2r/land_ice_segments/fit_statistics/n_seg_pulses',\n", + " 'gt2r/land_ice_segments/fit_statistics/sigma_h_mean',\n", + " 'gt2r/land_ice_segments/fit_statistics/signal_selection_source',\n", + " 'gt2r/land_ice_segments/fit_statistics/signal_selection_source_status',\n", + " 'gt2r/land_ice_segments/fit_statistics/snr',\n", + " 'gt2r/land_ice_segments/fit_statistics/snr_significance',\n", + " 'gt2r/land_ice_segments/fit_statistics/w_surface_window_final',\n", + " 'gt2r/land_ice_segments/geophysical/bckgrd',\n", + " 'gt2r/land_ice_segments/geophysical/bsnow_conf',\n", + " 'gt2r/land_ice_segments/geophysical/bsnow_h',\n", + " 'gt2r/land_ice_segments/geophysical/bsnow_od',\n", + " 'gt2r/land_ice_segments/geophysical/cloud_flg_asr',\n", + " 'gt2r/land_ice_segments/geophysical/cloud_flg_atm',\n", + " 'gt2r/land_ice_segments/geophysical/dac',\n", + " 'gt2r/land_ice_segments/geophysical/e_bckgrd',\n", + " 'gt2r/land_ice_segments/geophysical/layer_flag',\n", + " 'gt2r/land_ice_segments/geophysical/msw_flag',\n", + " 'gt2r/land_ice_segments/geophysical/neutat_delay_total',\n", + " 'gt2r/land_ice_segments/geophysical/r_eff',\n", + " 'gt2r/land_ice_segments/geophysical/solar_azimuth',\n", + " 'gt2r/land_ice_segments/geophysical/solar_elevation',\n", + " 'gt2r/land_ice_segments/geophysical/tide_earth',\n", + " 'gt2r/land_ice_segments/geophysical/tide_earth_free2mean',\n", + " 'gt2r/land_ice_segments/geophysical/tide_equilibrium',\n", + " 'gt2r/land_ice_segments/geophysical/tide_load',\n", + " 'gt2r/land_ice_segments/geophysical/tide_ocean',\n", + " 'gt2r/land_ice_segments/geophysical/tide_pole',\n", + " 'gt2r/land_ice_segments/ground_track/ref_azimuth',\n", + " 'gt2r/land_ice_segments/ground_track/ref_coelv',\n", + " 'gt2r/land_ice_segments/ground_track/seg_azimuth',\n", + " 'gt2r/land_ice_segments/ground_track/sigma_geo_at',\n", + " 'gt2r/land_ice_segments/ground_track/sigma_geo_r',\n", + " 'gt2r/land_ice_segments/ground_track/sigma_geo_xt',\n", + " 'gt2r/land_ice_segments/ground_track/x_atc',\n", + " 'gt2r/land_ice_segments/ground_track/y_atc',\n", + " 'gt2r/land_ice_segments/h_li',\n", + " 'gt2r/land_ice_segments/h_li_sigma',\n", + " 'gt2r/land_ice_segments/latitude',\n", + " 'gt2r/land_ice_segments/longitude',\n", + " 'gt2r/land_ice_segments/segment_id',\n", + " 'gt2r/land_ice_segments/sigma_geo_h',\n", + " 'gt2r/residual_histogram/bckgrd_per_m',\n", + " 'gt2r/residual_histogram/bin_top_h',\n", + " 'gt2r/residual_histogram/count',\n", + " 'gt2r/residual_histogram/delta_time',\n", + " 'gt2r/residual_histogram/ds_segment_id',\n", + " 'gt2r/residual_histogram/lat_mean',\n", + " 'gt2r/residual_histogram/lon_mean',\n", + " 'gt2r/residual_histogram/pulse_count',\n", + " 'gt2r/residual_histogram/segment_id_list',\n", + " 'gt2r/residual_histogram/x_atc_mean',\n", + " 'gt2r/segment_quality/delta_time',\n", + " 'gt2r/segment_quality/record_number',\n", + " 'gt2r/segment_quality/reference_pt_lat',\n", + " 'gt2r/segment_quality/reference_pt_lon',\n", + " 'gt2r/segment_quality/segment_id',\n", + " 'gt2r/segment_quality/signal_selection_source',\n", + " 'gt2r/segment_quality/signal_selection_status/signal_selection_status_all',\n", + " 'gt2r/segment_quality/signal_selection_status/signal_selection_status_backup',\n", + " 'gt2r/segment_quality/signal_selection_status/signal_selection_status_confident',\n", + " 'gt3l/land_ice_segments/atl06_quality_summary',\n", + " 'gt3l/land_ice_segments/bias_correction/fpb_mean_corr',\n", + " 'gt3l/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", + " 'gt3l/land_ice_segments/bias_correction/fpb_med_corr',\n", + " 'gt3l/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", + " 'gt3l/land_ice_segments/bias_correction/fpb_n_corr',\n", + " 'gt3l/land_ice_segments/bias_correction/med_r_fit',\n", + " 'gt3l/land_ice_segments/bias_correction/tx_mean_corr',\n", + " 'gt3l/land_ice_segments/bias_correction/tx_med_corr',\n", + " 'gt3l/land_ice_segments/delta_time',\n", + " 'gt3l/land_ice_segments/dem/dem_flag',\n", + " 'gt3l/land_ice_segments/dem/dem_h',\n", + " 'gt3l/land_ice_segments/dem/geoid_free2mean',\n", + " 'gt3l/land_ice_segments/dem/geoid_h',\n", + " 'gt3l/land_ice_segments/fit_statistics/dh_fit_dx',\n", + " 'gt3l/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", + " 'gt3l/land_ice_segments/fit_statistics/dh_fit_dy',\n", + " 'gt3l/land_ice_segments/fit_statistics/h_expected_rms',\n", + " 'gt3l/land_ice_segments/fit_statistics/h_mean',\n", + " 'gt3l/land_ice_segments/fit_statistics/h_rms_misfit',\n", + " 'gt3l/land_ice_segments/fit_statistics/h_robust_sprd',\n", + " 'gt3l/land_ice_segments/fit_statistics/n_fit_photons',\n", + " 'gt3l/land_ice_segments/fit_statistics/n_seg_pulses',\n", + " 'gt3l/land_ice_segments/fit_statistics/sigma_h_mean',\n", + " 'gt3l/land_ice_segments/fit_statistics/signal_selection_source',\n", + " 'gt3l/land_ice_segments/fit_statistics/signal_selection_source_status',\n", + " 'gt3l/land_ice_segments/fit_statistics/snr',\n", + " 'gt3l/land_ice_segments/fit_statistics/snr_significance',\n", + " 'gt3l/land_ice_segments/fit_statistics/w_surface_window_final',\n", + " 'gt3l/land_ice_segments/geophysical/bckgrd',\n", + " 'gt3l/land_ice_segments/geophysical/bsnow_conf',\n", + " 'gt3l/land_ice_segments/geophysical/bsnow_h',\n", + " 'gt3l/land_ice_segments/geophysical/bsnow_od',\n", + " 'gt3l/land_ice_segments/geophysical/cloud_flg_asr',\n", + " 'gt3l/land_ice_segments/geophysical/cloud_flg_atm',\n", + " 'gt3l/land_ice_segments/geophysical/dac',\n", + " 'gt3l/land_ice_segments/geophysical/e_bckgrd',\n", + " 'gt3l/land_ice_segments/geophysical/layer_flag',\n", + " 'gt3l/land_ice_segments/geophysical/msw_flag',\n", + " 'gt3l/land_ice_segments/geophysical/neutat_delay_total',\n", + " 'gt3l/land_ice_segments/geophysical/r_eff',\n", + " 'gt3l/land_ice_segments/geophysical/solar_azimuth',\n", + " 'gt3l/land_ice_segments/geophysical/solar_elevation',\n", + " 'gt3l/land_ice_segments/geophysical/tide_earth',\n", + " 'gt3l/land_ice_segments/geophysical/tide_earth_free2mean',\n", + " 'gt3l/land_ice_segments/geophysical/tide_equilibrium',\n", + " 'gt3l/land_ice_segments/geophysical/tide_load',\n", + " 'gt3l/land_ice_segments/geophysical/tide_ocean',\n", + " 'gt3l/land_ice_segments/geophysical/tide_pole',\n", + " 'gt3l/land_ice_segments/ground_track/ref_azimuth',\n", + " 'gt3l/land_ice_segments/ground_track/ref_coelv',\n", + " 'gt3l/land_ice_segments/ground_track/seg_azimuth',\n", + " 'gt3l/land_ice_segments/ground_track/sigma_geo_at',\n", + " 'gt3l/land_ice_segments/ground_track/sigma_geo_r',\n", + " 'gt3l/land_ice_segments/ground_track/sigma_geo_xt',\n", + " 'gt3l/land_ice_segments/ground_track/x_atc',\n", + " 'gt3l/land_ice_segments/ground_track/y_atc',\n", + " 'gt3l/land_ice_segments/h_li',\n", + " 'gt3l/land_ice_segments/h_li_sigma',\n", + " 'gt3l/land_ice_segments/latitude',\n", + " 'gt3l/land_ice_segments/longitude',\n", + " 'gt3l/land_ice_segments/segment_id',\n", + " 'gt3l/land_ice_segments/sigma_geo_h',\n", + " 'gt3l/residual_histogram/bckgrd_per_m',\n", + " 'gt3l/residual_histogram/bin_top_h',\n", + " 'gt3l/residual_histogram/count',\n", + " 'gt3l/residual_histogram/delta_time',\n", + " 'gt3l/residual_histogram/ds_segment_id',\n", + " 'gt3l/residual_histogram/lat_mean',\n", + " 'gt3l/residual_histogram/lon_mean',\n", + " 'gt3l/residual_histogram/pulse_count',\n", + " 'gt3l/residual_histogram/segment_id_list',\n", + " 'gt3l/residual_histogram/x_atc_mean',\n", + " 'gt3l/segment_quality/delta_time',\n", + " 'gt3l/segment_quality/record_number',\n", + " 'gt3l/segment_quality/reference_pt_lat',\n", + " 'gt3l/segment_quality/reference_pt_lon',\n", + " 'gt3l/segment_quality/segment_id',\n", + " 'gt3l/segment_quality/signal_selection_source',\n", + " 'gt3l/segment_quality/signal_selection_status/signal_selection_status_all',\n", + " 'gt3l/segment_quality/signal_selection_status/signal_selection_status_backup',\n", + " 'gt3l/segment_quality/signal_selection_status/signal_selection_status_confident',\n", + " 'gt3r/land_ice_segments/atl06_quality_summary',\n", + " 'gt3r/land_ice_segments/bias_correction/fpb_mean_corr',\n", + " 'gt3r/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", + " 'gt3r/land_ice_segments/bias_correction/fpb_med_corr',\n", + " 'gt3r/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", + " 'gt3r/land_ice_segments/bias_correction/fpb_n_corr',\n", + " 'gt3r/land_ice_segments/bias_correction/med_r_fit',\n", + " 'gt3r/land_ice_segments/bias_correction/tx_mean_corr',\n", + " 'gt3r/land_ice_segments/bias_correction/tx_med_corr',\n", + " 'gt3r/land_ice_segments/delta_time',\n", + " 'gt3r/land_ice_segments/dem/dem_flag',\n", + " 'gt3r/land_ice_segments/dem/dem_h',\n", + " 'gt3r/land_ice_segments/dem/geoid_free2mean',\n", + " 'gt3r/land_ice_segments/dem/geoid_h',\n", + " 'gt3r/land_ice_segments/fit_statistics/dh_fit_dx',\n", + " 'gt3r/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", + " 'gt3r/land_ice_segments/fit_statistics/dh_fit_dy',\n", + " 'gt3r/land_ice_segments/fit_statistics/h_expected_rms',\n", + " 'gt3r/land_ice_segments/fit_statistics/h_mean',\n", + " 'gt3r/land_ice_segments/fit_statistics/h_rms_misfit',\n", + " 'gt3r/land_ice_segments/fit_statistics/h_robust_sprd',\n", + " 'gt3r/land_ice_segments/fit_statistics/n_fit_photons',\n", + " 'gt3r/land_ice_segments/fit_statistics/n_seg_pulses',\n", + " 'gt3r/land_ice_segments/fit_statistics/sigma_h_mean',\n", + " 'gt3r/land_ice_segments/fit_statistics/signal_selection_source',\n", + " 'gt3r/land_ice_segments/fit_statistics/signal_selection_source_status',\n", + " 'gt3r/land_ice_segments/fit_statistics/snr',\n", + " 'gt3r/land_ice_segments/fit_statistics/snr_significance',\n", + " 'gt3r/land_ice_segments/fit_statistics/w_surface_window_final',\n", + " 'gt3r/land_ice_segments/geophysical/bckgrd',\n", + " 'gt3r/land_ice_segments/geophysical/bsnow_conf',\n", + " 'gt3r/land_ice_segments/geophysical/bsnow_h',\n", + " 'gt3r/land_ice_segments/geophysical/bsnow_od',\n", + " 'gt3r/land_ice_segments/geophysical/cloud_flg_asr',\n", + " 'gt3r/land_ice_segments/geophysical/cloud_flg_atm',\n", + " 'gt3r/land_ice_segments/geophysical/dac',\n", + " 'gt3r/land_ice_segments/geophysical/e_bckgrd',\n", + " 'gt3r/land_ice_segments/geophysical/layer_flag',\n", + " 'gt3r/land_ice_segments/geophysical/msw_flag',\n", + " 'gt3r/land_ice_segments/geophysical/neutat_delay_total',\n", + " 'gt3r/land_ice_segments/geophysical/r_eff',\n", + " 'gt3r/land_ice_segments/geophysical/solar_azimuth',\n", + " 'gt3r/land_ice_segments/geophysical/solar_elevation',\n", + " 'gt3r/land_ice_segments/geophysical/tide_earth',\n", + " 'gt3r/land_ice_segments/geophysical/tide_earth_free2mean',\n", + " 'gt3r/land_ice_segments/geophysical/tide_equilibrium',\n", + " 'gt3r/land_ice_segments/geophysical/tide_load',\n", + " 'gt3r/land_ice_segments/geophysical/tide_ocean',\n", + " 'gt3r/land_ice_segments/geophysical/tide_pole',\n", + " 'gt3r/land_ice_segments/ground_track/ref_azimuth',\n", + " 'gt3r/land_ice_segments/ground_track/ref_coelv',\n", + " 'gt3r/land_ice_segments/ground_track/seg_azimuth',\n", + " 'gt3r/land_ice_segments/ground_track/sigma_geo_at',\n", + " 'gt3r/land_ice_segments/ground_track/sigma_geo_r',\n", + " 'gt3r/land_ice_segments/ground_track/sigma_geo_xt',\n", + " 'gt3r/land_ice_segments/ground_track/x_atc',\n", + " 'gt3r/land_ice_segments/ground_track/y_atc',\n", + " 'gt3r/land_ice_segments/h_li',\n", + " 'gt3r/land_ice_segments/h_li_sigma',\n", + " 'gt3r/land_ice_segments/latitude',\n", + " 'gt3r/land_ice_segments/longitude',\n", + " 'gt3r/land_ice_segments/segment_id',\n", + " 'gt3r/land_ice_segments/sigma_geo_h',\n", + " 'gt3r/residual_histogram/bckgrd_per_m',\n", + " 'gt3r/residual_histogram/bin_top_h',\n", + " 'gt3r/residual_histogram/count',\n", + " 'gt3r/residual_histogram/delta_time',\n", + " 'gt3r/residual_histogram/ds_segment_id',\n", + " 'gt3r/residual_histogram/lat_mean',\n", + " 'gt3r/residual_histogram/lon_mean',\n", + " 'gt3r/residual_histogram/pulse_count',\n", + " 'gt3r/residual_histogram/segment_id_list',\n", + " 'gt3r/residual_histogram/x_atc_mean',\n", + " 'gt3r/segment_quality/delta_time',\n", + " 'gt3r/segment_quality/record_number',\n", + " 'gt3r/segment_quality/reference_pt_lat',\n", + " 'gt3r/segment_quality/reference_pt_lon',\n", + " 'gt3r/segment_quality/segment_id',\n", + " 'gt3r/segment_quality/signal_selection_source',\n", + " 'gt3r/segment_quality/signal_selection_status/signal_selection_status_all',\n", + " 'gt3r/segment_quality/signal_selection_status/signal_selection_status_backup',\n", + " 'gt3r/segment_quality/signal_selection_status/signal_selection_status_confident',\n", + " 'orbit_info/bounding_polygon_lat1',\n", + " 'orbit_info/bounding_polygon_lon1',\n", + " 'orbit_info/crossing_time',\n", + " 'orbit_info/cycle_number',\n", + " 'orbit_info/lan',\n", + " 'orbit_info/orbit_number',\n", + " 'orbit_info/rgt',\n", + " 'orbit_info/sc_orient',\n", + " 'orbit_info/sc_orient_time',\n", + " 'quality_assessment/gt1l/delta_time',\n", + " 'quality_assessment/gt1l/lat_mean',\n", + " 'quality_assessment/gt1l/lon_mean',\n", + " 'quality_assessment/gt1l/signal_selection_source_fraction_0',\n", + " 'quality_assessment/gt1l/signal_selection_source_fraction_1',\n", + " 'quality_assessment/gt1l/signal_selection_source_fraction_2',\n", + " 'quality_assessment/gt1l/signal_selection_source_fraction_3',\n", + " 'quality_assessment/gt1r/delta_time',\n", + " 'quality_assessment/gt1r/lat_mean',\n", + " 'quality_assessment/gt1r/lon_mean',\n", + " 'quality_assessment/gt1r/signal_selection_source_fraction_0',\n", + " 'quality_assessment/gt1r/signal_selection_source_fraction_1',\n", + " 'quality_assessment/gt1r/signal_selection_source_fraction_2',\n", + " 'quality_assessment/gt1r/signal_selection_source_fraction_3',\n", + " 'quality_assessment/gt2l/delta_time',\n", + " 'quality_assessment/gt2l/lat_mean',\n", + " 'quality_assessment/gt2l/lon_mean',\n", + " 'quality_assessment/gt2l/signal_selection_source_fraction_0',\n", + " 'quality_assessment/gt2l/signal_selection_source_fraction_1',\n", + " 'quality_assessment/gt2l/signal_selection_source_fraction_2',\n", + " 'quality_assessment/gt2l/signal_selection_source_fraction_3',\n", + " 'quality_assessment/gt2r/delta_time',\n", + " 'quality_assessment/gt2r/lat_mean',\n", + " 'quality_assessment/gt2r/lon_mean',\n", + " 'quality_assessment/gt2r/signal_selection_source_fraction_0',\n", + " 'quality_assessment/gt2r/signal_selection_source_fraction_1',\n", + " 'quality_assessment/gt2r/signal_selection_source_fraction_2',\n", + " 'quality_assessment/gt2r/signal_selection_source_fraction_3',\n", + " 'quality_assessment/gt3l/delta_time',\n", + " 'quality_assessment/gt3l/lat_mean',\n", + " 'quality_assessment/gt3l/lon_mean',\n", + " 'quality_assessment/gt3l/signal_selection_source_fraction_0',\n", + " 'quality_assessment/gt3l/signal_selection_source_fraction_1',\n", + " 'quality_assessment/gt3l/signal_selection_source_fraction_2',\n", + " 'quality_assessment/gt3l/signal_selection_source_fraction_3',\n", + " 'quality_assessment/gt3r/delta_time',\n", + " 'quality_assessment/gt3r/lat_mean',\n", + " 'quality_assessment/gt3r/lon_mean',\n", + " 'quality_assessment/gt3r/signal_selection_source_fraction_0',\n", + " 'quality_assessment/gt3r/signal_selection_source_fraction_1',\n", + " 'quality_assessment/gt3r/signal_selection_source_fraction_2',\n", + " 'quality_assessment/gt3r/signal_selection_source_fraction_3',\n", + " 'quality_assessment/qa_granule_fail_reason',\n", + " 'quality_assessment/qa_granule_pass_fail']" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "reader.vars.avail()" ] @@ -333,7 +1610,9 @@ { "cell_type": "markdown", "id": "b2449941", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "To make things easier, you can use icepyx's built-in default list that loads commonly used variables for your non-gridded data product, or create your own list of variables to be read in.\n", "icepyx will determine what variables are available for you to read in by creating a list from one of your source files.\n", @@ -349,7 +1628,9 @@ { "cell_type": "markdown", "id": "55092d1b", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "For a basic case, let's say we want to read in height, latitude, and longitude for all beam pairs.\n", "We create our variables list as" @@ -357,7 +1638,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 28, "id": "e3734e09", "metadata": {}, "outputs": [], @@ -368,17 +1649,53 @@ { "cell_type": "markdown", "id": "fff0bb19", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "Then we can view a dictionary of the variables we'd like to read in." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "id": "e5456e36", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'sc_orient': ['orbit_info/sc_orient'],\n", + " 'atlas_sdp_gps_epoch': ['ancillary_data/atlas_sdp_gps_epoch'],\n", + " 'cycle_number': ['orbit_info/cycle_number'],\n", + " 'rgt': ['orbit_info/rgt'],\n", + " 'data_start_utc': ['ancillary_data/data_start_utc'],\n", + " 'data_end_utc': ['ancillary_data/data_end_utc'],\n", + " 'h_li': ['gt1l/land_ice_segments/h_li',\n", + " 'gt1r/land_ice_segments/h_li',\n", + " 'gt2l/land_ice_segments/h_li',\n", + " 'gt2r/land_ice_segments/h_li',\n", + " 'gt3l/land_ice_segments/h_li',\n", + " 'gt3r/land_ice_segments/h_li'],\n", + " 'latitude': ['gt1l/land_ice_segments/latitude',\n", + " 'gt1r/land_ice_segments/latitude',\n", + " 'gt2l/land_ice_segments/latitude',\n", + " 'gt2r/land_ice_segments/latitude',\n", + " 'gt3l/land_ice_segments/latitude',\n", + " 'gt3r/land_ice_segments/latitude'],\n", + " 'longitude': ['gt1l/land_ice_segments/longitude',\n", + " 'gt1r/land_ice_segments/longitude',\n", + " 'gt2l/land_ice_segments/longitude',\n", + " 'gt2r/land_ice_segments/longitude',\n", + " 'gt3l/land_ice_segments/longitude',\n", + " 'gt3r/land_ice_segments/longitude']}" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "reader.vars.wanted" ] @@ -386,14 +1703,16 @@ { "cell_type": "markdown", "id": "9d5b50b5", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "Don't forget - if you need to start over, and re-generate your wanted variables list, it's easy!" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "id": "69894391", "metadata": {}, "outputs": [], @@ -404,7 +1723,9 @@ { "cell_type": "markdown", "id": "473de4d7", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "### Step 5: Loading your data\n", "\n", @@ -414,9 +1735,120 @@ { "cell_type": "code", "execution_count": null, - "id": "eaabc976", + "id": "4a66d889-8d2d-4b9a-821a-96a394ff8d66", "metadata": {}, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "eaabc976", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", + " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n", + "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", + " .rename({\"delta_time\": \"photon_idx\"})\n" + ] + } + ], "source": [ "ds = reader.load()" ] @@ -424,7 +1856,9 @@ { "cell_type": "markdown", "id": "db6560f1", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "Within a Jupyter Notebook, you can get a summary view of your data object.\n", "\n", @@ -435,10 +1869,549 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "id": "723256f7", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:              (photon_idx: 29027, spot: 2, gran_idx: 6)\n",
+       "Coordinates:\n",
+       "  * photon_idx           (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n",
+       "  * spot                 (spot) uint8 2 5\n",
+       "  * gran_idx             (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n",
+       "    source_file          (gran_idx) <U72 '../../../../data/ATL06/processed_AT...\n",
+       "    delta_time           (gran_idx, photon_idx) datetime64[ns] 2019-02-22T01:...\n",
+       "Data variables:\n",
+       "    sc_orient            (gran_idx) int8 0 0 0 1 1 1\n",
+       "    cycle_number         (gran_idx) int8 2 2 2 5 5 5\n",
+       "    rgt                  (gran_idx) int16 849 902 910 986 1001 1016\n",
+       "    atlas_sdp_gps_epoch  (gran_idx) datetime64[ns] 2018-01-01T00:00:18 ... 20...\n",
+       "    data_start_utc       (gran_idx) datetime64[ns] 2019-02-22T01:03:44.199777...\n",
+       "    data_end_utc         (gran_idx) datetime64[ns] 2019-02-22T01:07:38.112326...\n",
+       "    h_li                 (spot, gran_idx, photon_idx) float32 nan nan ... nan\n",
+       "    latitude             (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
+       "    longitude            (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
+       "    gt                   (gran_idx, spot) <U4 'gt3r' 'gt1l' ... 'gt1l' 'gt3r'\n",
+       "Attributes:\n",
+       "    data_product:  ATL06\n",
+       "    Description:   The land_ice_height group contains the primary set of deri...\n",
+       "    data_rate:     Data within this group are sparse.  Data values are provid...
" + ], + "text/plain": [ + "\n", + "Dimensions: (photon_idx: 29027, spot: 2, gran_idx: 6)\n", + "Coordinates:\n", + " * photon_idx (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n", + " * spot (spot) uint8 2 5\n", + " * gran_idx (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n", + " source_file (gran_idx) " + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "ds.plot.scatter(x=\"longitude\", y=\"latitude\", hue=\"h_li\", vmin=-100, vmax=2000)" ] @@ -469,7 +2455,9 @@ { "cell_type": "markdown", "id": "6421f67c", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "A developer note to users:\n", "our next steps will be to create an xarray extension with ICESat-2 aware functions (like \"get_strong_beams\", etc.).\n", @@ -478,191 +2466,39 @@ }, { "cell_type": "markdown", - "id": "6edfbb25", - "metadata": {}, - "source": [ - "### More on Intake catalogs and the read object\n", - "\n", - "As anyone familiar with ICESat-2 hdf5 files knows, one of the challenges to reading in data is looping through all of the beam pairs for each track.\n", - "The icepyx read module takes advantage of icepyx's variables module, which has some awareness of ICESat-2 data and uses that to save the user the trouble of having to loop through each beam pair.\n", - "The `reader.load()` function does this by automatically creating minimal Intake catalogs for each variable path, reading in the data, and merging each variable into a ready-to-analyze Xarray DataSet.\n", - "The Intake savvy user may wish to view the template catalog or use an existing catalog." - ] - }, - { - "cell_type": "markdown", - "id": "0f0076f9", - "metadata": {}, - "source": [ - "#### Viewing the template catalog\n", - "\n", - "You can access the ICESat-2 catalog template as an attribute of the read object.\n", - "\n", - "***NOTE: accessing `reader.is2catalog` creates a template with a placeholder in the 'group' parameter; thus, it will not work to actually read in data***" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2de29fd8", + "id": "1b0cb477", "metadata": { - "scrolled": true + "user_expressions": [] }, - "outputs": [], - "source": [ - "reader.is2catalog" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a5deef8", - "metadata": {}, - "outputs": [], - "source": [ - "reader.is2catalog.gui" - ] - }, - { - "cell_type": "markdown", - "id": "fef43556", - "metadata": {}, - "source": [ - "#### Use an existing catalog\n", - "If you already have a catalog for your data, you can supply that when you create the read object." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64986a60", - "metadata": {}, - "outputs": [], - "source": [ - "catpath = path_root + 'test_catalog.yml'\n", - "reader = ipx.Read(filepath, pattern, catpath)" - ] - }, - { - "cell_type": "markdown", - "id": "cf930e0a", - "metadata": {}, - "source": [ - "Then, you can use the catalog you supplied by calling intake's `read` directly to read in the specified data variable." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd0e086a", - "metadata": {}, - "outputs": [], - "source": [ - "ds = reader.is2catalog.read()" - ] - }, - { - "cell_type": "markdown", - "id": "60b1a304", - "metadata": {}, "source": [ - "***NOTE: this means that you will only be able to read in a single data variable!***\n", - "\n", - "To take advantage of icepyx's knowledge of ICESat-2 data nesting of beam pairs and read in multiple related variables at once, you must use the variable approach outlined earlier in this tutorial." + "#### Credits\n", + "* original notebook by: Jessica Scheick\n", + "* notebook contributors: Wei Ji and Tian\n", + "* templates for default ICESat-2 Intake catalogs from: [Wei Ji](https://github.com/icesat2py/icepyx/issues/106) and [Tian](https://github.com/icetianli/ICESat2_xarray)." ] }, { "cell_type": "code", "execution_count": null, - "id": "f5e3a221", - "metadata": {}, - "outputs": [], - "source": [ - "ds = reader.load()\n", - "ds" - ] - }, - { - "cell_type": "markdown", - "id": "d56fc41c", + "id": "aaf6f5a6-355b-456a-99fd-ce0b51045b58", "metadata": {}, - "source": [ - "### More customization options\n", - "\n", - "If you'd like to use the icepyx ICESat-2 Catalog template to create your own customized catalog, we recommend that you access the `build_catalog` function directly, which returns an Intake Catalog instance.\n", - "\n", - "You'll need to supply the required `data_source`, `path_pattern`, and `source_type` arguments. `data_source` and `path_pattern` are described in Steps 2 and 3 of this tutorial. `source_type` is the string you'd like to use for your Local Catalog entry.\n", - "\n", - "This function accepts as keyword input arguments (kwargs) dictionaries with appropriate keys (depending on the Intake driver you are using).\n", - "The simplest version of this is specifying the variable parameters and paths of interest.\n", - "`grp_paths` may contain \"variables\", each of which must then be further defined by `grp_path_params`.\n", - "You cannot use glob-like path syntax to access variables (so `grp_path = '/*/land_ice_segments'` is NOT VALID)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f174f885", - "metadata": { - "scrolled": true - }, "outputs": [], - "source": [ - "import icepyx.core.is2cat as is2cat\n", - "\n", - "# build a custom ICESat-2 catalog with a group and parameter\n", - "cat = is2cat.build_catalog(data_source = path_root,\n", - " path_pattern = pattern,\n", - " source_type = \"manual_catalog\",\n", - " grp_paths = \"/{{gt}}/land_ice_segments\",\n", - " grp_path_params = [{\"name\": \"gt\",\n", - " \"description\": \"Ground track\",\n", - " \"type\": \"str\",\n", - " \"default\": \"gt1l\",\n", - " \"allowed\": [\"gt1l\", \"gt1r\", \"gt2l\", \"gt2r\", \"gt3l\", \"gt3r\"]\n", - " }]\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "bab9c949", - "metadata": {}, - "source": [ - "#### Saving your catalog\n", - "If you create a highly customized ICESat-2 catalog, you can use Intake's `save` to export it as a .yml file.\n", - "\n", - "Don't forget you can easily use an existing catalog (such as this highly customized one you just made) to read in your data with `reader = ipx.Read(filepath, pattern, catalog)` (so it's as easy as re-creating your reader object with your modified catalog)." - ] + "source": [] }, { "cell_type": "code", "execution_count": null, - "id": "30f0122a", + "id": "8ea1987f-b6bf-44df-a869-949290f498cb", "metadata": {}, "outputs": [], - "source": [ - "catpath = path_root + 'test_catalog.yml'\n", - "cat.save(catpath)" - ] - }, - { - "cell_type": "markdown", - "id": "1b0cb477", - "metadata": {}, - "source": [ - "#### Credits\n", - "* original notebook by: Jessica Scheick\n", - "* notebook contributors: Wei Ji and Tian\n", - "* templates for default ICESat-2 Intake catalogs from: [Wei Ji](https://github.com/icesat2py/icepyx/issues/106) and [Tian](https://github.com/icetianli/ICESat2_xarray)." - ] + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "general", "language": "python", - "name": "python3" + "name": "general" }, "language_info": { "codemirror_mode": { @@ -674,7 +2510,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.11.4" } }, "nbformat": 4, diff --git a/doc/source/user_guide/documentation/read.rst b/doc/source/user_guide/documentation/read.rst index b076ef210..a5beedf4e 100644 --- a/doc/source/user_guide/documentation/read.rst +++ b/doc/source/user_guide/documentation/read.rst @@ -19,7 +19,6 @@ Attributes .. autosummary:: :toctree: ../../_icepyx/ - Read.is2catalog Read.vars From 9f066112c8b73200128e18eed8e6242d15329da6 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 20:52:51 +0000 Subject: [PATCH 07/30] update approach paragraph --- doc/source/example_notebooks/IS2_data_read-in.ipynb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index b8697b1d7..c459b7c78 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -22,10 +22,7 @@ "Instead of needing to manually iterate through the beam pairs, you can provide a few options to the `Read` object and icepyx will do the heavy lifting for you (as detailed in this notebook).\n", "\n", "### Approach\n", - "If you're interested in what's happening under the hood: icepyx turns your instructions into something called a catalog, then uses the Intake library and the catalog to actually load the data into memory. Specifically, icepyx creates an [Intake](https://intake.readthedocs.io/en/latest/) data [catalog](https://intake.readthedocs.io/en/latest/catalog.html) for each requested variable and then merges the read-in data from each of the variables to create a single data object.\n", - "\n", - "Intake catalogs are powerful (and the tool we selected) because they can be saved, shared, modified, and reused to reproducibly read in a set of data files in a consistent way as part of an analysis workflow.\n", - "This approach streamlines the transition between data sources (local/downloaded files or, ultimately, cloud/bucket access) and data object types (e.g. [Xarray Dataset](http://xarray.pydata.org/en/stable/generated/xarray.Dataset.html) or [GeoPandas GeoDataFrame](https://geopandas.org/docs/reference/api/geopandas.GeoDataFrame.html))." + "If you're interested in what's happening under the hood: icepyx uses the [xarray](https://docs.xarray.dev/en/stable/) library to read in each of the requested variables of the dataset. icepyx formats each requested variable and then merges the read-in data from each of the variables to create a single data object. The use of xarray is powerful, because the returned data object can be used with relevant xarray processing tools." ] }, { From d019b9a2db2391882dbc69c4816f64eb03f389e3 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 20:59:03 +0000 Subject: [PATCH 08/30] remove one more instance of catalog from the docs --- doc/source/example_notebooks/IS2_data_read-in.ipynb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index c459b7c78..13b49cddb 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -2470,8 +2470,7 @@ "source": [ "#### Credits\n", "* original notebook by: Jessica Scheick\n", - "* notebook contributors: Wei Ji and Tian\n", - "* templates for default ICESat-2 Intake catalogs from: [Wei Ji](https://github.com/icesat2py/icepyx/issues/106) and [Tian](https://github.com/icetianli/ICESat2_xarray)." + "* notebook contributors: Wei Ji and Tian" ] }, { From 156ea89103f44dd4b7be680ac51eecb5e1b85b18 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Wed, 30 Aug 2023 21:01:36 +0000 Subject: [PATCH 09/30] clear jupyter history --- .../example_notebooks/IS2_data_read-in.ipynb | 2019 +---------------- 1 file changed, 34 insertions(+), 1985 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index 13b49cddb..115c63044 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "2b74b672", "metadata": {}, "outputs": [], @@ -58,18 +58,10 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "id": "c4390195", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You have 6 files matching the filename pattern to be read in.\n" - ] - } - ], + "outputs": [], "source": [ "path_root = '/full/path/to/your/data/'\n", "pattern = \"processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"\n", @@ -78,7 +70,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "2f46029d", "metadata": {}, "outputs": [], @@ -88,603 +80,10 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "c0439388", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:              (photon_idx: 29027, spot: 2, gran_idx: 6)\n",
-       "Coordinates:\n",
-       "  * photon_idx           (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n",
-       "  * spot                 (spot) uint8 2 5\n",
-       "  * gran_idx             (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n",
-       "    source_file          (gran_idx) <U72 '../../../../data/ATL06/processed_AT...\n",
-       "    delta_time           (gran_idx, photon_idx) datetime64[ns] 2019-02-22T01:...\n",
-       "Data variables:\n",
-       "    sc_orient            (gran_idx) int8 0 0 0 1 1 1\n",
-       "    cycle_number         (gran_idx) int8 2 2 2 5 5 5\n",
-       "    rgt                  (gran_idx) int16 849 902 910 986 1001 1016\n",
-       "    atlas_sdp_gps_epoch  (gran_idx) datetime64[ns] 2018-01-01T00:00:18 ... 20...\n",
-       "    data_start_utc       (gran_idx) datetime64[ns] 2019-02-22T01:03:44.199777...\n",
-       "    data_end_utc         (gran_idx) datetime64[ns] 2019-02-22T01:07:38.112326...\n",
-       "    h_li                 (spot, gran_idx, photon_idx) float32 nan nan ... nan\n",
-       "    latitude             (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
-       "    longitude            (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
-       "    gt                   (gran_idx, spot) <U4 'gt3r' 'gt1l' ... 'gt1l' 'gt3r'\n",
-       "Attributes:\n",
-       "    data_product:  ATL06\n",
-       "    Description:   The land_ice_height group contains the primary set of deri...\n",
-       "    data_rate:     Data within this group are sparse.  Data values are provid...
" - ], - "text/plain": [ - "\n", - "Dimensions: (photon_idx: 29027, spot: 2, gran_idx: 6)\n", - "Coordinates:\n", - " * photon_idx (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n", - " * spot (spot) uint8 2 5\n", - " * gran_idx (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n", - " source_file (gran_idx) " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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p6cDkJKSwvTp0x0u16GA59ixY7z44os8/PDDJCQkALBq1SoOHjxoVzlvvfUWUVFRLFiwgNatW1OzZk3uuusu6tSpY83zwgsvcPfdd/P222/TvHlzateuTe/evQkNDXWk6kIIIYT7lXB31o0yMjL48ssveeyxx2x2I9+wYQOhoaHUq1ePESNGWD/jAaKjo8nMzKR79+7WtMjISBo3bsyWLVucq9B1Xn/9dT7++GM++eQTm1WW27dvz+7dux0u1+6AZ+PGjTRp0oTt27fz/fffk5qaCsC+ffuYOnWqXWUtX76cVq1aMWDAAEJDQ2nevDmffPKJ9byu6/z000/Uq1ePHj16EBoaSps2bVi2bFm+Zaanp5OcnGxzCCGEEKWKi8bwKKVyfebltIgUZNmyZVy6dInhw4db03r16sXixYv59ddfmTlzJjt37uTOO++0lhcfH4+Pjw+VK1e2KSssLIz4+Hhn/ho2Dh06RMeOHXOlBwUFcenSJYfLtTvgef7553n99ddZu3YtPj4+1vQuXbqwdetWu8r6559/+Oijj6hbty6rV6/mqaeeYsyYMSxatAiAhIQEUlNTefPNN+nZsydr1qzhvvvuo3///rmWm84xY8YMTCaT9YiKirL3EoUQQogyIT4+3uYzz2QyMWPGjEIfN3/+fHr16kVkZKQ17cEHH6R37940btyYe+65h5UrV3L48GF++umnAstSStm0EjkrIiKCo0eP5krfvHkztWvXdrhcu6el79+/n6+++ipXetWqVblw4YJdZem6TqtWrax9cs2bN+fgwYN89NFHDB061LrgYb9+/Rg3bhwAzZo1Y8uWLXz88cc2/Y45pkyZwvjx462/JycnS9AjhBCiVHHF1hKagvDwcA4dOmST7uvrW+DjTpw4wbp16/j+++8LzBcREUGNGjU4cuQIYHmujIwMEhMTbVp5EhISaN++vYNXkdvIkSN59tln+eyzz9A0jdOnT7N161YmTpzIyy+/7HC5drfwVKpUiTNnzuRK37NnDzfddJNdZUVERNCoUSObtIYNG1pnYIWEhODl5VVgnhv5+voSFBRkcwghhBCljgvG8Gialuszr7CAZ8GCBYSGhtK7d+8C8124cIGTJ08SEREBQMuWLfH29rbO7gI4c+YMBw4ccGnAM3nyZO699166dOlCamoqHTt25IknnmDkyJGMHj3a4XLt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vbs1LTIyksaNG7Nlyxan6lPcpIVHCJGLpnnn+bMQwkVctHmoUork5GSbZF9fX3x9fQt+qFKMHz+e22+/ncaNG1vTe/XqxYABA6hRowYxMTG89NJL3HnnnURHR+Pr60t8fDw+Pj5UrlzZprywsDDi4+OdvKDiJQGPEEIIUUbFx8djMpls0qZOncq0adMKfNzo0aPZt28fmzdvtkl/8MEHrT83btyYVq1aUaNGDX766Sf69++fb3llYY89CXiEEEKIEuaqrSXCw8NzzbQqrHXnmWeeYfny5fz2229Uq1atwLwRERHUqFGDI0eOABAeHk5GRgaJiYk2rTwJCQm0b1/ALM9SQMbwCCGEEO7g9MKDlnF3QUFBNkd+AY9SitGjR/P999/z66+/UqtWrUKreOHCBU6ePElERAQALVu2xNvbm7Vr11rznDlzhgMHDpT6gEdaeIQQQoiSplPiu6U//fTTfPXVV/zwww9UrFjROubGZDLh7+9Pamoq06ZN4/777yciIoLjx4/z73//m5CQEO677z5r3scff5wJEyZQpUoVgoODmThxIk2aNLHO2iqtJOARQgghyoGPPvoIgM6dO9ukL1iwgOHDh2M0Gtm/fz+LFi3i0qVLRERE0KVLF7755hsqVqxozT979my8vLwYOHAgaWlp3HXXXSxcuBCjsXTP5HR7wBMXF8dzzz3HypUrSUtLo169esyfP5+WLVuSmZnJiy++yM8//8w///yDyWSia9euvPnmm0RGRrq76kIIIYRDNFwzhsceqpD8/v7+rF69utBy/Pz8eP/993n//fften53c+sYnsTERDp06IC3tzcrV67kzz//ZObMmVSqVAmAK1eusHv3bl566SV2797N999/z+HDh+nbt687qy2EEEI4xyUbh8pmWvZwawvPW2+9RVRUFAsWLLCm1axZ0/qzyWSyGRgF8P7779O6dWtiY2OpXr16SVVVCCGEcB2F87udS7xjF7e28CxfvpxWrVoxYMAAQkNDad68OZ988kmBj0lKSkLTNGsrkBBCCCFEYdwa8Pzzzz989NFH1K1bl9WrV/PUU08xZswYFi1alGf+q1ev8vzzzzNo0CCCgoLyzJOenk5ycrLNIYQQQpQqimsztRw9pIXHLm7t0tJ1nVatWjF9+nQAmjdvzsGDB/noo48YOnSoTd7MzEweeughdF3nww8/zLfM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rb7++us8y1i8eLHy8fHJld61a1c1cuTIYrmWd999V7Vv397anx4TE1Ngl8mWLVsUoHbt2mVXfZQqmdfG3uvJ8Z///EcFBQXle96Vr01xXo873juuvBZ3v2/suZ4c586dU4cOHVJr1qxRHTp0UHfffbfSdT1Xue547xTXteQo6feNKN08uoVn9OjRhc4cqFmzZp7pbdu2BeDo0aNUqVLFmv7nn39y5513MmLEiHy/NRSkRYsWeHt7c+TIEVq0aGHXY115PeHh4Wzfvt0mT2JiIpmZmbm+weYIDw8nIyODxMREm29ECQkJtG/f3o4rKfq1vP7662zbti3XcvGtWrVi8ODBfP755zbpn376Kc2aNaNly5Z21QdK5rWx93pytG3bluTkZM6ePZvn6+PK16a4rsdd7x1XXou73zf2XE+OkJAQQkJCqFevHg0bNiQqKopt27bRrl07m8e4471TXNeSo6TfN6KUc3fEVVr9+OOPClAnTpywph04cECFhoaqSZMmOVzu/v37FaA2btzoimoW2Y3XkzP48vTp09Y8S5YsKdLgy2+++caadvr06WId4HfixAm1f/9+67F69WoFqG+//VadPHnSJm9KSoqqUKFCobN/8lMSr40913O9999/X/n5+amrV6/med4dr41SRb+esvDeKcq1lJX3TX5iY2MVoNavX2+TXhbeOzfK71quV1rfN8I9JOBRlqbcWbNmqT179qh//vlHffPNNyoyMlL17dvXmienKX7w4ME2Ux4TEhKseU6dOqXq16+vtm/frpRS6ujRo+qVV15RO3fuVDExMeqnn35SDRo0UM2bNy/WKY9FuZ6c6bV33XWX2r17t1q3bp2qVq2azfTaG69HKcsUzmrVqql169ap3bt3qzvvvLNEp3AW1GXy6aefKj8/P3Xx4sVc50rLa3OjvK5n+fLlat68eWr//v3q6NGj6pNPPlFBQUFqzJgx+V6PUu5/bfK7nrL03insWsrS+2b79u3q/fffV3v27FHHjx9Xv/76q7r99ttVnTp1cgUApf29U5RrKcvvG1EyJOBRSkVHR6s2bdook8mk/Pz8VP369dXUqVPV5cuXrXny62uuUaOGNU/ODTLnG0dsbKzq2LGjCg4OVj4+PqpOnTpqzJgx6sKFC26/HqUs32h79+6t/P39VXBwsBo9erTNjfDG61FKqbS0NDV69GgVHBys/P39VZ8+fVRsbGyxXs/1Cgp42rVrpwYNGlTg49z92uRXr+uvZ+XKlapZs2aqQoUKKiAgQDVu3FjNmTNHZWZm5ns9Srn/tbm+XtdfT1l67xR2LUqVnffNvn37VJcuXVRwcLDy9fVVNWvWVE899ZQ6depUrryl/b1TlGspy+8bUTJkt3QhhBBCeDxZh0cIIYQQHk8CHiGEEEJ4PAl4hBBCCOHxJOARQgghhMeTgEcIIYQQHk8CHiGEEEJ4PAl4hBBCCOHxJOARQgghhMeTgEeIQhw/fhxN09i7d2+xlK9pGsuWLXP48Rs2bEDTNDRN49577y0wb+fOnRk7dqzDzyUKlvM6VKpUyd1VEULcQAIeUaoNHz680A/x4hYVFcWZM2do3LgxcC3AuHTpklvrdaNDhw6xcOFCd1ejXMjv3+WZM2eYM2dOiddHCFE4CXiEKITRaCQ8PBwvLy93V6VAoaGhpaJlITMz091VcJvw8HBMJpO7qyGEyIMEPKJM27hxI61bt8bX15eIiAief/55srKyrOc7d+7MmDFjmDx5MsHBwYSHhzNt2jSbMv7++29uv/12/Pz8aNSoEevWrbPpZrq+S+v48eN06dIFgMqVK6NpGsOHDwegZs2aub7dN2vWzOb5jhw5QseOHa3PtXbt2lzXFBcXx4MPPkjlypWpUqUK/fr14/jx43b/bS5fvszQoUOpUKECERERzJw5M1eejIwMJk+ezE033URgYCBt2rRhw4YNNnk++eQToqKiCAgI4L777mPWrFk2gdW0adNo1qwZn332GbVr18bX1xelFElJSTz55JOEhoYSFBTEnXfeyR9//GFT9o8//kjLli3x8/Ojdu3avPLKKzav37Rp06hevTq+vr5ERkYyZsyYIl17Ydd14cIFHn74YapVq0ZAQABNmjTh66+/tinj22+/pUmTJvj7+1OlShW6du3K5cuXmTZtGp9//jk//PCDtQvrxr+ZEKL0Kd1fWYUoQFxcHHfffTfDhw9n0aJF/P3334wYMQI/Pz+bIOPzzz9n/PjxbN++na1btzJ8+HA6dOhAt27d0HWde++9l+rVq7N9+3ZSUlKYMGFCvs8ZFRXFd999x/3338+hQ4cICgrC39+/SPXVdZ3+/fsTEhLCtm3bSE5OzjWe5sqVK3Tp0oU77riD3377DS8vL15//XV69uzJvn378PHxKfLfZ9KkSaxfv56lS5cSHh7Ov//9b6Kjo2nWrJk1z6OPPsrx48dZsmQJkZGRLF26lJ49e7J//37q1q3L77//zlNPPcVbb71F3759WbduHS+99FKu5zp69Cj//e9/+e677zAajQD07t2b4OBgfv75Z0wmE3PnzuWuu+7i8OHDBAcHs3r1ah555BHee+897rjjDo4dO8aTTz4JwNSpU/n222+ZPXs2S5Ys4ZZbbiE+Pj5XwJSfwq7r6tWrtGzZkueee46goCB++uknhgwZQu3atWnTpg1nzpzh4Ycf5u233+a+++4jJSWFTZs2oZRi4sSJ/PXXXyQnJ7NgwQIAgoODi/y6CCHcxL2btQtRsGHDhql+/frlee7f//63ql+/vtJ13Zr2f//3f6pChQrKbDYrpZTq1KmTuv32220ed9ttt6nnnntOKaXUypUrlZeXlzpz5oz1/Nq1axWgli5dqpRSKiYmRgFqz549Siml1q9frwCVmJhoU26NGjXU7NmzbdKaNm2qpk6dqpRSavXq1cpoNKqTJ09az69cudLmuebPn5/rmtLT05W/v79avXp1nn+HvOqTkpKifHx81JIlS6xpFy5cUP7+/urZZ59VSil19OhRpWmaiouLsynvrrvuUlOmTFFKKfXggw+q3r1725wfPHiwMplM1t+nTp2qvL29VUJCgjXtl19+UUFBQerq1as2j61Tp46aO3euUkqpO+64Q02fPt3m/BdffKEiIiKUUkrNnDlT1atXT2VkZOR53fkpynXl5e6771YTJkxQSikVHR2tAHX8+PE88xb073LBggU2fx8hROkgLTyizPrrr79o164dmqZZ0zp06EBqaiqnTp2ievXqANx66602j4uIiCAhIQGwDPSNiooiPDzcer5169bFVt/q1atTrVo1a1q7du1s8kRHR3P06FEqVqxok3716lWOHTtW5Oc6duwYGRkZNuUHBwdTv3596++7d+9GKUW9evVsHpuenk6VKlUAy9/nvvvusznfunVrVqxYYZNWo0YNqlatanMdqamp1nJypKWlWa8jOjqanTt38sYbb1jPm81mrl69ypUrVxgwYABz5syhdu3a9OzZk7vvvpt77rmn0LFURbkus9nMm2++yTfffENcXBzp6emkp6cTGBgIQNOmTbnrrrto0qQJPXr0oHv37jzwwANUrly5wOcWQpReEvCI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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "ds.plot.scatter(x=\"longitude\", y=\"latitude\", hue=\"h_li\", vmin=-100, vmax=2000)" ] @@ -754,7 +132,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "63da2b3c", "metadata": {}, "outputs": [], @@ -765,24 +143,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "e6f7c047", "metadata": {}, - "outputs": [ - { - "ename": "AttributeError", - "evalue": "'Query' object has no attribute '_session'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[10], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mregion_a\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdownload_granules\u001b[49m\u001b[43m(\u001b[49m\u001b[43mpath\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpath_root\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/envs/general/lib/python3.11/site-packages/icepyx/core/query.py:1129\u001b[0m, in \u001b[0;36mQuery.download_granules\u001b[0;34m(self, path, verbose, subset, restart, **kwargs)\u001b[0m\n\u001b[1;32m 1124\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 1125\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m (\n\u001b[1;32m 1126\u001b[0m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mhasattr\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124morderIDs\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 1127\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39morderIDs) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m\n\u001b[1;32m 1128\u001b[0m ):\n\u001b[0;32m-> 1129\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43morder_granules\u001b[49m\u001b[43m(\u001b[49m\u001b[43mverbose\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mverbose\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msubset\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msubset\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1131\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39mdownload(verbose, path, session\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_session, restart\u001b[38;5;241m=\u001b[39mrestart)\n", - "File \u001b[0;32m~/envs/general/lib/python3.11/site-packages/icepyx/core/query.py:1065\u001b[0m, in \u001b[0;36mQuery.order_granules\u001b[0;34m(self, verbose, subset, email, **kwargs)\u001b[0m\n\u001b[1;32m 1048\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39mplace_order(\n\u001b[1;32m 1049\u001b[0m tempCMRparams,\n\u001b[1;32m 1050\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreqparams,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 1055\u001b[0m geom_filepath\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_spatial\u001b[38;5;241m.\u001b[39m_geom_file,\n\u001b[1;32m 1056\u001b[0m )\n\u001b[1;32m 1058\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 1059\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_granules\u001b[38;5;241m.\u001b[39mplace_order(\n\u001b[1;32m 1060\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mCMRparams,\n\u001b[1;32m 1061\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mreqparams,\n\u001b[1;32m 1062\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msubsetparams(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs),\n\u001b[1;32m 1063\u001b[0m verbose,\n\u001b[1;32m 1064\u001b[0m subset,\n\u001b[0;32m-> 1065\u001b[0m session\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_session\u001b[49m,\n\u001b[1;32m 1066\u001b[0m geom_filepath\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_spatial\u001b[38;5;241m.\u001b[39m_geom_file,\n\u001b[1;32m 1067\u001b[0m )\n", - "\u001b[0;31mAttributeError\u001b[0m: 'Query' object has no attribute '_session'" - ] - } - ], + "outputs": [], "source": [ "region_a.download_granules(path=path_root)" ] @@ -823,7 +187,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "9cde6679", "metadata": {}, "outputs": [], @@ -833,7 +197,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "8b6edf0c", "metadata": {}, "outputs": [], @@ -843,7 +207,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "e683ebf7", "metadata": {}, "outputs": [], @@ -870,7 +234,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "7318abd0", "metadata": {}, "outputs": [], @@ -881,7 +245,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "f43e8664", "metadata": {}, "outputs": [], @@ -891,7 +255,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "id": "992a77fb", "metadata": {}, "outputs": [], @@ -901,7 +265,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "id": "6aec1a70", "metadata": {}, "outputs": [], @@ -928,46 +292,22 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "id": "39bd7eb8", "metadata": { "scrolled": true }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You have 6 files matching the filename pattern to be read in.\n" - ] - } - ], + "outputs": [], "source": [ "reader = ipx.Read(data_source=path_root, product=\"ATL06\", filename_pattern=pattern) # or ipx.Read(filepath, \"ATLXX\") if your filenames match the default pattern" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "id": "6c9ebc4a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['../../../../data/ATL06/processed_ATL06_20190226005526_09100205_006_02.h5',\n", - " '../../../../data/ATL06/processed_ATL06_20191201105502_10010505_006_01.h5',\n", - " '../../../../data/ATL06/processed_ATL06_20190225121032_09020203_006_02.h5',\n", - " '../../../../data/ATL06/processed_ATL06_20190222010344_08490205_006_02.h5',\n", - " '../../../../data/ATL06/processed_ATL06_20191130112041_09860505_006_01.h5',\n", - " '../../../../data/ATL06/processed_ATL06_20191202102922_10160505_006_01.h5']" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "reader._filelist" ] @@ -990,616 +330,12 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "id": "18f65f67", "metadata": { "scrolled": true }, - "outputs": [ - { - "data": { - "text/plain": [ - "['ancillary_data/atlas_sdp_gps_epoch',\n", - " 'ancillary_data/control',\n", - " 'ancillary_data/data_end_utc',\n", - " 'ancillary_data/data_start_utc',\n", - " 'ancillary_data/end_cycle',\n", - " 'ancillary_data/end_delta_time',\n", - " 'ancillary_data/end_geoseg',\n", - " 'ancillary_data/end_gpssow',\n", - " 'ancillary_data/end_gpsweek',\n", - " 'ancillary_data/end_orbit',\n", - " 'ancillary_data/end_region',\n", - " 'ancillary_data/end_rgt',\n", - " 'ancillary_data/granule_end_utc',\n", - " 'ancillary_data/granule_start_utc',\n", - " 'ancillary_data/land_ice/dt_hist',\n", - " 'ancillary_data/land_ice/fit_maxiter',\n", - " 'ancillary_data/land_ice/fpb_maxiter',\n", - " 'ancillary_data/land_ice/max_res_ids',\n", - " 'ancillary_data/land_ice/min_dist',\n", - " 'ancillary_data/land_ice/min_gain_th',\n", - " 'ancillary_data/land_ice/min_n_pe',\n", - " 'ancillary_data/land_ice/min_n_sel',\n", - " 'ancillary_data/land_ice/min_signal_conf',\n", - " 'ancillary_data/land_ice/n_hist',\n", - " 'ancillary_data/land_ice/n_sigmas',\n", - " 'ancillary_data/land_ice/nhist_bins',\n", - " 'ancillary_data/land_ice/proc_interval',\n", - " 'ancillary_data/land_ice/qs_lim_bsc',\n", - " 'ancillary_data/land_ice/qs_lim_hrs',\n", - " 'ancillary_data/land_ice/qs_lim_hsigma',\n", - " 'ancillary_data/land_ice/qs_lim_msw',\n", - " 'ancillary_data/land_ice/qs_lim_snr',\n", - " 'ancillary_data/land_ice/qs_lim_sss',\n", - " 'ancillary_data/land_ice/rbin_width',\n", - " 'ancillary_data/land_ice/sigma_beam',\n", - " 'ancillary_data/land_ice/sigma_tx',\n", - " 'ancillary_data/land_ice/t_dead',\n", - " 'ancillary_data/land_ice/txp_maxiter',\n", - " 'ancillary_data/qa_at_interval',\n", - " 'ancillary_data/release',\n", - " 'ancillary_data/start_cycle',\n", - " 'ancillary_data/start_delta_time',\n", - " 'ancillary_data/start_geoseg',\n", - " 'ancillary_data/start_gpssow',\n", - " 'ancillary_data/start_gpsweek',\n", - " 'ancillary_data/start_orbit',\n", - " 'ancillary_data/start_region',\n", - " 'ancillary_data/start_rgt',\n", - " 'ancillary_data/version',\n", - " 'gt1l/land_ice_segments/atl06_quality_summary',\n", - " 'gt1l/land_ice_segments/bias_correction/fpb_mean_corr',\n", - " 'gt1l/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", - " 'gt1l/land_ice_segments/bias_correction/fpb_med_corr',\n", - " 'gt1l/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", - " 'gt1l/land_ice_segments/bias_correction/fpb_n_corr',\n", - " 'gt1l/land_ice_segments/bias_correction/med_r_fit',\n", - " 'gt1l/land_ice_segments/bias_correction/tx_mean_corr',\n", - " 'gt1l/land_ice_segments/bias_correction/tx_med_corr',\n", - " 'gt1l/land_ice_segments/delta_time',\n", - " 'gt1l/land_ice_segments/dem/dem_flag',\n", - " 'gt1l/land_ice_segments/dem/dem_h',\n", - " 'gt1l/land_ice_segments/dem/geoid_free2mean',\n", - " 'gt1l/land_ice_segments/dem/geoid_h',\n", - " 'gt1l/land_ice_segments/fit_statistics/dh_fit_dx',\n", - " 'gt1l/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", - " 'gt1l/land_ice_segments/fit_statistics/dh_fit_dy',\n", - " 'gt1l/land_ice_segments/fit_statistics/h_expected_rms',\n", - " 'gt1l/land_ice_segments/fit_statistics/h_mean',\n", - " 'gt1l/land_ice_segments/fit_statistics/h_rms_misfit',\n", - " 'gt1l/land_ice_segments/fit_statistics/h_robust_sprd',\n", - " 'gt1l/land_ice_segments/fit_statistics/n_fit_photons',\n", - " 'gt1l/land_ice_segments/fit_statistics/n_seg_pulses',\n", - " 'gt1l/land_ice_segments/fit_statistics/sigma_h_mean',\n", - " 'gt1l/land_ice_segments/fit_statistics/signal_selection_source',\n", - " 'gt1l/land_ice_segments/fit_statistics/signal_selection_source_status',\n", - " 'gt1l/land_ice_segments/fit_statistics/snr',\n", - " 'gt1l/land_ice_segments/fit_statistics/snr_significance',\n", - " 'gt1l/land_ice_segments/fit_statistics/w_surface_window_final',\n", - " 'gt1l/land_ice_segments/geophysical/bckgrd',\n", - " 'gt1l/land_ice_segments/geophysical/bsnow_conf',\n", - " 'gt1l/land_ice_segments/geophysical/bsnow_h',\n", - " 'gt1l/land_ice_segments/geophysical/bsnow_od',\n", - " 'gt1l/land_ice_segments/geophysical/cloud_flg_asr',\n", - " 'gt1l/land_ice_segments/geophysical/cloud_flg_atm',\n", - " 'gt1l/land_ice_segments/geophysical/dac',\n", - " 'gt1l/land_ice_segments/geophysical/e_bckgrd',\n", - " 'gt1l/land_ice_segments/geophysical/layer_flag',\n", - " 'gt1l/land_ice_segments/geophysical/msw_flag',\n", - " 'gt1l/land_ice_segments/geophysical/neutat_delay_total',\n", - " 'gt1l/land_ice_segments/geophysical/r_eff',\n", - " 'gt1l/land_ice_segments/geophysical/solar_azimuth',\n", - " 'gt1l/land_ice_segments/geophysical/solar_elevation',\n", - " 'gt1l/land_ice_segments/geophysical/tide_earth',\n", - " 'gt1l/land_ice_segments/geophysical/tide_earth_free2mean',\n", - " 'gt1l/land_ice_segments/geophysical/tide_equilibrium',\n", - " 'gt1l/land_ice_segments/geophysical/tide_load',\n", - " 'gt1l/land_ice_segments/geophysical/tide_ocean',\n", - " 'gt1l/land_ice_segments/geophysical/tide_pole',\n", - " 'gt1l/land_ice_segments/ground_track/ref_azimuth',\n", - " 'gt1l/land_ice_segments/ground_track/ref_coelv',\n", - " 'gt1l/land_ice_segments/ground_track/seg_azimuth',\n", - " 'gt1l/land_ice_segments/ground_track/sigma_geo_at',\n", - " 'gt1l/land_ice_segments/ground_track/sigma_geo_r',\n", - " 'gt1l/land_ice_segments/ground_track/sigma_geo_xt',\n", - " 'gt1l/land_ice_segments/ground_track/x_atc',\n", - " 'gt1l/land_ice_segments/ground_track/y_atc',\n", - " 'gt1l/land_ice_segments/h_li',\n", - " 'gt1l/land_ice_segments/h_li_sigma',\n", - " 'gt1l/land_ice_segments/latitude',\n", - " 'gt1l/land_ice_segments/longitude',\n", - " 'gt1l/land_ice_segments/segment_id',\n", - " 'gt1l/land_ice_segments/sigma_geo_h',\n", - " 'gt1l/residual_histogram/bckgrd_per_m',\n", - " 'gt1l/residual_histogram/bin_top_h',\n", - " 'gt1l/residual_histogram/count',\n", - " 'gt1l/residual_histogram/delta_time',\n", - " 'gt1l/residual_histogram/ds_segment_id',\n", - " 'gt1l/residual_histogram/lat_mean',\n", - " 'gt1l/residual_histogram/lon_mean',\n", - " 'gt1l/residual_histogram/pulse_count',\n", - " 'gt1l/residual_histogram/segment_id_list',\n", - " 'gt1l/residual_histogram/x_atc_mean',\n", - " 'gt1l/segment_quality/delta_time',\n", - " 'gt1l/segment_quality/record_number',\n", - " 'gt1l/segment_quality/reference_pt_lat',\n", - " 'gt1l/segment_quality/reference_pt_lon',\n", - " 'gt1l/segment_quality/segment_id',\n", - " 'gt1l/segment_quality/signal_selection_source',\n", - " 'gt1l/segment_quality/signal_selection_status/signal_selection_status_all',\n", - " 'gt1l/segment_quality/signal_selection_status/signal_selection_status_backup',\n", - " 'gt1l/segment_quality/signal_selection_status/signal_selection_status_confident',\n", - " 'gt1r/land_ice_segments/atl06_quality_summary',\n", - " 'gt1r/land_ice_segments/bias_correction/fpb_mean_corr',\n", - " 'gt1r/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", - " 'gt1r/land_ice_segments/bias_correction/fpb_med_corr',\n", - " 'gt1r/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", - " 'gt1r/land_ice_segments/bias_correction/fpb_n_corr',\n", - " 'gt1r/land_ice_segments/bias_correction/med_r_fit',\n", - " 'gt1r/land_ice_segments/bias_correction/tx_mean_corr',\n", - " 'gt1r/land_ice_segments/bias_correction/tx_med_corr',\n", - " 'gt1r/land_ice_segments/delta_time',\n", - " 'gt1r/land_ice_segments/dem/dem_flag',\n", - " 'gt1r/land_ice_segments/dem/dem_h',\n", - " 'gt1r/land_ice_segments/dem/geoid_free2mean',\n", - " 'gt1r/land_ice_segments/dem/geoid_h',\n", - " 'gt1r/land_ice_segments/fit_statistics/dh_fit_dx',\n", - " 'gt1r/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", - " 'gt1r/land_ice_segments/fit_statistics/dh_fit_dy',\n", - " 'gt1r/land_ice_segments/fit_statistics/h_expected_rms',\n", - " 'gt1r/land_ice_segments/fit_statistics/h_mean',\n", - " 'gt1r/land_ice_segments/fit_statistics/h_rms_misfit',\n", - " 'gt1r/land_ice_segments/fit_statistics/h_robust_sprd',\n", - " 'gt1r/land_ice_segments/fit_statistics/n_fit_photons',\n", - " 'gt1r/land_ice_segments/fit_statistics/n_seg_pulses',\n", - " 'gt1r/land_ice_segments/fit_statistics/sigma_h_mean',\n", - " 'gt1r/land_ice_segments/fit_statistics/signal_selection_source',\n", - " 'gt1r/land_ice_segments/fit_statistics/signal_selection_source_status',\n", - " 'gt1r/land_ice_segments/fit_statistics/snr',\n", - " 'gt1r/land_ice_segments/fit_statistics/snr_significance',\n", - " 'gt1r/land_ice_segments/fit_statistics/w_surface_window_final',\n", - " 'gt1r/land_ice_segments/geophysical/bckgrd',\n", - " 'gt1r/land_ice_segments/geophysical/bsnow_conf',\n", - " 'gt1r/land_ice_segments/geophysical/bsnow_h',\n", - " 'gt1r/land_ice_segments/geophysical/bsnow_od',\n", - " 'gt1r/land_ice_segments/geophysical/cloud_flg_asr',\n", - " 'gt1r/land_ice_segments/geophysical/cloud_flg_atm',\n", - " 'gt1r/land_ice_segments/geophysical/dac',\n", - " 'gt1r/land_ice_segments/geophysical/e_bckgrd',\n", - " 'gt1r/land_ice_segments/geophysical/layer_flag',\n", - " 'gt1r/land_ice_segments/geophysical/msw_flag',\n", - " 'gt1r/land_ice_segments/geophysical/neutat_delay_total',\n", - " 'gt1r/land_ice_segments/geophysical/r_eff',\n", - " 'gt1r/land_ice_segments/geophysical/solar_azimuth',\n", - " 'gt1r/land_ice_segments/geophysical/solar_elevation',\n", - " 'gt1r/land_ice_segments/geophysical/tide_earth',\n", - " 'gt1r/land_ice_segments/geophysical/tide_earth_free2mean',\n", - " 'gt1r/land_ice_segments/geophysical/tide_equilibrium',\n", - " 'gt1r/land_ice_segments/geophysical/tide_load',\n", - " 'gt1r/land_ice_segments/geophysical/tide_ocean',\n", - " 'gt1r/land_ice_segments/geophysical/tide_pole',\n", - " 'gt1r/land_ice_segments/ground_track/ref_azimuth',\n", - " 'gt1r/land_ice_segments/ground_track/ref_coelv',\n", - " 'gt1r/land_ice_segments/ground_track/seg_azimuth',\n", - " 'gt1r/land_ice_segments/ground_track/sigma_geo_at',\n", - " 'gt1r/land_ice_segments/ground_track/sigma_geo_r',\n", - " 'gt1r/land_ice_segments/ground_track/sigma_geo_xt',\n", - " 'gt1r/land_ice_segments/ground_track/x_atc',\n", - " 'gt1r/land_ice_segments/ground_track/y_atc',\n", - " 'gt1r/land_ice_segments/h_li',\n", - " 'gt1r/land_ice_segments/h_li_sigma',\n", - " 'gt1r/land_ice_segments/latitude',\n", - " 'gt1r/land_ice_segments/longitude',\n", - " 'gt1r/land_ice_segments/segment_id',\n", - " 'gt1r/land_ice_segments/sigma_geo_h',\n", - " 'gt1r/residual_histogram/bckgrd_per_m',\n", - " 'gt1r/residual_histogram/bin_top_h',\n", - " 'gt1r/residual_histogram/count',\n", - " 'gt1r/residual_histogram/delta_time',\n", - " 'gt1r/residual_histogram/ds_segment_id',\n", - " 'gt1r/residual_histogram/lat_mean',\n", - " 'gt1r/residual_histogram/lon_mean',\n", - " 'gt1r/residual_histogram/pulse_count',\n", - " 'gt1r/residual_histogram/segment_id_list',\n", - " 'gt1r/residual_histogram/x_atc_mean',\n", - " 'gt1r/segment_quality/delta_time',\n", - " 'gt1r/segment_quality/record_number',\n", - " 'gt1r/segment_quality/reference_pt_lat',\n", - " 'gt1r/segment_quality/reference_pt_lon',\n", - " 'gt1r/segment_quality/segment_id',\n", - " 'gt1r/segment_quality/signal_selection_source',\n", - " 'gt1r/segment_quality/signal_selection_status/signal_selection_status_all',\n", - " 'gt1r/segment_quality/signal_selection_status/signal_selection_status_backup',\n", - " 'gt1r/segment_quality/signal_selection_status/signal_selection_status_confident',\n", - " 'gt2l/land_ice_segments/atl06_quality_summary',\n", - " 'gt2l/land_ice_segments/bias_correction/fpb_mean_corr',\n", - " 'gt2l/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", - " 'gt2l/land_ice_segments/bias_correction/fpb_med_corr',\n", - " 'gt2l/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", - " 'gt2l/land_ice_segments/bias_correction/fpb_n_corr',\n", - " 'gt2l/land_ice_segments/bias_correction/med_r_fit',\n", - " 'gt2l/land_ice_segments/bias_correction/tx_mean_corr',\n", - " 'gt2l/land_ice_segments/bias_correction/tx_med_corr',\n", - " 'gt2l/land_ice_segments/delta_time',\n", - " 'gt2l/land_ice_segments/dem/dem_flag',\n", - " 'gt2l/land_ice_segments/dem/dem_h',\n", - " 'gt2l/land_ice_segments/dem/geoid_free2mean',\n", - " 'gt2l/land_ice_segments/dem/geoid_h',\n", - " 'gt2l/land_ice_segments/fit_statistics/dh_fit_dx',\n", - " 'gt2l/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", - " 'gt2l/land_ice_segments/fit_statistics/dh_fit_dy',\n", - " 'gt2l/land_ice_segments/fit_statistics/h_expected_rms',\n", - " 'gt2l/land_ice_segments/fit_statistics/h_mean',\n", - " 'gt2l/land_ice_segments/fit_statistics/h_rms_misfit',\n", - " 'gt2l/land_ice_segments/fit_statistics/h_robust_sprd',\n", - " 'gt2l/land_ice_segments/fit_statistics/n_fit_photons',\n", - " 'gt2l/land_ice_segments/fit_statistics/n_seg_pulses',\n", - " 'gt2l/land_ice_segments/fit_statistics/sigma_h_mean',\n", - " 'gt2l/land_ice_segments/fit_statistics/signal_selection_source',\n", - " 'gt2l/land_ice_segments/fit_statistics/signal_selection_source_status',\n", - " 'gt2l/land_ice_segments/fit_statistics/snr',\n", - " 'gt2l/land_ice_segments/fit_statistics/snr_significance',\n", - " 'gt2l/land_ice_segments/fit_statistics/w_surface_window_final',\n", - " 'gt2l/land_ice_segments/geophysical/bckgrd',\n", - " 'gt2l/land_ice_segments/geophysical/bsnow_conf',\n", - " 'gt2l/land_ice_segments/geophysical/bsnow_h',\n", - " 'gt2l/land_ice_segments/geophysical/bsnow_od',\n", - " 'gt2l/land_ice_segments/geophysical/cloud_flg_asr',\n", - " 'gt2l/land_ice_segments/geophysical/cloud_flg_atm',\n", - " 'gt2l/land_ice_segments/geophysical/dac',\n", - " 'gt2l/land_ice_segments/geophysical/e_bckgrd',\n", - " 'gt2l/land_ice_segments/geophysical/layer_flag',\n", - " 'gt2l/land_ice_segments/geophysical/msw_flag',\n", - " 'gt2l/land_ice_segments/geophysical/neutat_delay_total',\n", - " 'gt2l/land_ice_segments/geophysical/r_eff',\n", - " 'gt2l/land_ice_segments/geophysical/solar_azimuth',\n", - " 'gt2l/land_ice_segments/geophysical/solar_elevation',\n", - " 'gt2l/land_ice_segments/geophysical/tide_earth',\n", - " 'gt2l/land_ice_segments/geophysical/tide_earth_free2mean',\n", - " 'gt2l/land_ice_segments/geophysical/tide_equilibrium',\n", - " 'gt2l/land_ice_segments/geophysical/tide_load',\n", - " 'gt2l/land_ice_segments/geophysical/tide_ocean',\n", - " 'gt2l/land_ice_segments/geophysical/tide_pole',\n", - " 'gt2l/land_ice_segments/ground_track/ref_azimuth',\n", - " 'gt2l/land_ice_segments/ground_track/ref_coelv',\n", - " 'gt2l/land_ice_segments/ground_track/seg_azimuth',\n", - " 'gt2l/land_ice_segments/ground_track/sigma_geo_at',\n", - " 'gt2l/land_ice_segments/ground_track/sigma_geo_r',\n", - " 'gt2l/land_ice_segments/ground_track/sigma_geo_xt',\n", - " 'gt2l/land_ice_segments/ground_track/x_atc',\n", - " 'gt2l/land_ice_segments/ground_track/y_atc',\n", - " 'gt2l/land_ice_segments/h_li',\n", - " 'gt2l/land_ice_segments/h_li_sigma',\n", - " 'gt2l/land_ice_segments/latitude',\n", - " 'gt2l/land_ice_segments/longitude',\n", - " 'gt2l/land_ice_segments/segment_id',\n", - " 'gt2l/land_ice_segments/sigma_geo_h',\n", - " 'gt2l/residual_histogram/bckgrd_per_m',\n", - " 'gt2l/residual_histogram/bin_top_h',\n", - " 'gt2l/residual_histogram/count',\n", - " 'gt2l/residual_histogram/delta_time',\n", - " 'gt2l/residual_histogram/ds_segment_id',\n", - " 'gt2l/residual_histogram/lat_mean',\n", - " 'gt2l/residual_histogram/lon_mean',\n", - " 'gt2l/residual_histogram/pulse_count',\n", - " 'gt2l/residual_histogram/segment_id_list',\n", - " 'gt2l/residual_histogram/x_atc_mean',\n", - " 'gt2l/segment_quality/delta_time',\n", - " 'gt2l/segment_quality/record_number',\n", - " 'gt2l/segment_quality/reference_pt_lat',\n", - " 'gt2l/segment_quality/reference_pt_lon',\n", - " 'gt2l/segment_quality/segment_id',\n", - " 'gt2l/segment_quality/signal_selection_source',\n", - " 'gt2l/segment_quality/signal_selection_status/signal_selection_status_all',\n", - " 'gt2l/segment_quality/signal_selection_status/signal_selection_status_backup',\n", - " 'gt2l/segment_quality/signal_selection_status/signal_selection_status_confident',\n", - " 'gt2r/land_ice_segments/atl06_quality_summary',\n", - " 'gt2r/land_ice_segments/bias_correction/fpb_mean_corr',\n", - " 'gt2r/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", - " 'gt2r/land_ice_segments/bias_correction/fpb_med_corr',\n", - " 'gt2r/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", - " 'gt2r/land_ice_segments/bias_correction/fpb_n_corr',\n", - " 'gt2r/land_ice_segments/bias_correction/med_r_fit',\n", - " 'gt2r/land_ice_segments/bias_correction/tx_mean_corr',\n", - " 'gt2r/land_ice_segments/bias_correction/tx_med_corr',\n", - " 'gt2r/land_ice_segments/delta_time',\n", - " 'gt2r/land_ice_segments/dem/dem_flag',\n", - " 'gt2r/land_ice_segments/dem/dem_h',\n", - " 'gt2r/land_ice_segments/dem/geoid_free2mean',\n", - " 'gt2r/land_ice_segments/dem/geoid_h',\n", - " 'gt2r/land_ice_segments/fit_statistics/dh_fit_dx',\n", - " 'gt2r/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", - " 'gt2r/land_ice_segments/fit_statistics/dh_fit_dy',\n", - " 'gt2r/land_ice_segments/fit_statistics/h_expected_rms',\n", - " 'gt2r/land_ice_segments/fit_statistics/h_mean',\n", - " 'gt2r/land_ice_segments/fit_statistics/h_rms_misfit',\n", - " 'gt2r/land_ice_segments/fit_statistics/h_robust_sprd',\n", - " 'gt2r/land_ice_segments/fit_statistics/n_fit_photons',\n", - " 'gt2r/land_ice_segments/fit_statistics/n_seg_pulses',\n", - " 'gt2r/land_ice_segments/fit_statistics/sigma_h_mean',\n", - " 'gt2r/land_ice_segments/fit_statistics/signal_selection_source',\n", - " 'gt2r/land_ice_segments/fit_statistics/signal_selection_source_status',\n", - " 'gt2r/land_ice_segments/fit_statistics/snr',\n", - " 'gt2r/land_ice_segments/fit_statistics/snr_significance',\n", - " 'gt2r/land_ice_segments/fit_statistics/w_surface_window_final',\n", - " 'gt2r/land_ice_segments/geophysical/bckgrd',\n", - " 'gt2r/land_ice_segments/geophysical/bsnow_conf',\n", - " 'gt2r/land_ice_segments/geophysical/bsnow_h',\n", - " 'gt2r/land_ice_segments/geophysical/bsnow_od',\n", - " 'gt2r/land_ice_segments/geophysical/cloud_flg_asr',\n", - " 'gt2r/land_ice_segments/geophysical/cloud_flg_atm',\n", - " 'gt2r/land_ice_segments/geophysical/dac',\n", - " 'gt2r/land_ice_segments/geophysical/e_bckgrd',\n", - " 'gt2r/land_ice_segments/geophysical/layer_flag',\n", - " 'gt2r/land_ice_segments/geophysical/msw_flag',\n", - " 'gt2r/land_ice_segments/geophysical/neutat_delay_total',\n", - " 'gt2r/land_ice_segments/geophysical/r_eff',\n", - " 'gt2r/land_ice_segments/geophysical/solar_azimuth',\n", - " 'gt2r/land_ice_segments/geophysical/solar_elevation',\n", - " 'gt2r/land_ice_segments/geophysical/tide_earth',\n", - " 'gt2r/land_ice_segments/geophysical/tide_earth_free2mean',\n", - " 'gt2r/land_ice_segments/geophysical/tide_equilibrium',\n", - " 'gt2r/land_ice_segments/geophysical/tide_load',\n", - " 'gt2r/land_ice_segments/geophysical/tide_ocean',\n", - " 'gt2r/land_ice_segments/geophysical/tide_pole',\n", - " 'gt2r/land_ice_segments/ground_track/ref_azimuth',\n", - " 'gt2r/land_ice_segments/ground_track/ref_coelv',\n", - " 'gt2r/land_ice_segments/ground_track/seg_azimuth',\n", - " 'gt2r/land_ice_segments/ground_track/sigma_geo_at',\n", - " 'gt2r/land_ice_segments/ground_track/sigma_geo_r',\n", - " 'gt2r/land_ice_segments/ground_track/sigma_geo_xt',\n", - " 'gt2r/land_ice_segments/ground_track/x_atc',\n", - " 'gt2r/land_ice_segments/ground_track/y_atc',\n", - " 'gt2r/land_ice_segments/h_li',\n", - " 'gt2r/land_ice_segments/h_li_sigma',\n", - " 'gt2r/land_ice_segments/latitude',\n", - " 'gt2r/land_ice_segments/longitude',\n", - " 'gt2r/land_ice_segments/segment_id',\n", - " 'gt2r/land_ice_segments/sigma_geo_h',\n", - " 'gt2r/residual_histogram/bckgrd_per_m',\n", - " 'gt2r/residual_histogram/bin_top_h',\n", - " 'gt2r/residual_histogram/count',\n", - " 'gt2r/residual_histogram/delta_time',\n", - " 'gt2r/residual_histogram/ds_segment_id',\n", - " 'gt2r/residual_histogram/lat_mean',\n", - " 'gt2r/residual_histogram/lon_mean',\n", - " 'gt2r/residual_histogram/pulse_count',\n", - " 'gt2r/residual_histogram/segment_id_list',\n", - " 'gt2r/residual_histogram/x_atc_mean',\n", - " 'gt2r/segment_quality/delta_time',\n", - " 'gt2r/segment_quality/record_number',\n", - " 'gt2r/segment_quality/reference_pt_lat',\n", - " 'gt2r/segment_quality/reference_pt_lon',\n", - " 'gt2r/segment_quality/segment_id',\n", - " 'gt2r/segment_quality/signal_selection_source',\n", - " 'gt2r/segment_quality/signal_selection_status/signal_selection_status_all',\n", - " 'gt2r/segment_quality/signal_selection_status/signal_selection_status_backup',\n", - " 'gt2r/segment_quality/signal_selection_status/signal_selection_status_confident',\n", - " 'gt3l/land_ice_segments/atl06_quality_summary',\n", - " 'gt3l/land_ice_segments/bias_correction/fpb_mean_corr',\n", - " 'gt3l/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", - " 'gt3l/land_ice_segments/bias_correction/fpb_med_corr',\n", - " 'gt3l/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", - " 'gt3l/land_ice_segments/bias_correction/fpb_n_corr',\n", - " 'gt3l/land_ice_segments/bias_correction/med_r_fit',\n", - " 'gt3l/land_ice_segments/bias_correction/tx_mean_corr',\n", - " 'gt3l/land_ice_segments/bias_correction/tx_med_corr',\n", - " 'gt3l/land_ice_segments/delta_time',\n", - " 'gt3l/land_ice_segments/dem/dem_flag',\n", - " 'gt3l/land_ice_segments/dem/dem_h',\n", - " 'gt3l/land_ice_segments/dem/geoid_free2mean',\n", - " 'gt3l/land_ice_segments/dem/geoid_h',\n", - " 'gt3l/land_ice_segments/fit_statistics/dh_fit_dx',\n", - " 'gt3l/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", - " 'gt3l/land_ice_segments/fit_statistics/dh_fit_dy',\n", - " 'gt3l/land_ice_segments/fit_statistics/h_expected_rms',\n", - " 'gt3l/land_ice_segments/fit_statistics/h_mean',\n", - " 'gt3l/land_ice_segments/fit_statistics/h_rms_misfit',\n", - " 'gt3l/land_ice_segments/fit_statistics/h_robust_sprd',\n", - " 'gt3l/land_ice_segments/fit_statistics/n_fit_photons',\n", - " 'gt3l/land_ice_segments/fit_statistics/n_seg_pulses',\n", - " 'gt3l/land_ice_segments/fit_statistics/sigma_h_mean',\n", - " 'gt3l/land_ice_segments/fit_statistics/signal_selection_source',\n", - " 'gt3l/land_ice_segments/fit_statistics/signal_selection_source_status',\n", - " 'gt3l/land_ice_segments/fit_statistics/snr',\n", - " 'gt3l/land_ice_segments/fit_statistics/snr_significance',\n", - " 'gt3l/land_ice_segments/fit_statistics/w_surface_window_final',\n", - " 'gt3l/land_ice_segments/geophysical/bckgrd',\n", - " 'gt3l/land_ice_segments/geophysical/bsnow_conf',\n", - " 'gt3l/land_ice_segments/geophysical/bsnow_h',\n", - " 'gt3l/land_ice_segments/geophysical/bsnow_od',\n", - " 'gt3l/land_ice_segments/geophysical/cloud_flg_asr',\n", - " 'gt3l/land_ice_segments/geophysical/cloud_flg_atm',\n", - " 'gt3l/land_ice_segments/geophysical/dac',\n", - " 'gt3l/land_ice_segments/geophysical/e_bckgrd',\n", - " 'gt3l/land_ice_segments/geophysical/layer_flag',\n", - " 'gt3l/land_ice_segments/geophysical/msw_flag',\n", - " 'gt3l/land_ice_segments/geophysical/neutat_delay_total',\n", - " 'gt3l/land_ice_segments/geophysical/r_eff',\n", - " 'gt3l/land_ice_segments/geophysical/solar_azimuth',\n", - " 'gt3l/land_ice_segments/geophysical/solar_elevation',\n", - " 'gt3l/land_ice_segments/geophysical/tide_earth',\n", - " 'gt3l/land_ice_segments/geophysical/tide_earth_free2mean',\n", - " 'gt3l/land_ice_segments/geophysical/tide_equilibrium',\n", - " 'gt3l/land_ice_segments/geophysical/tide_load',\n", - " 'gt3l/land_ice_segments/geophysical/tide_ocean',\n", - " 'gt3l/land_ice_segments/geophysical/tide_pole',\n", - " 'gt3l/land_ice_segments/ground_track/ref_azimuth',\n", - " 'gt3l/land_ice_segments/ground_track/ref_coelv',\n", - " 'gt3l/land_ice_segments/ground_track/seg_azimuth',\n", - " 'gt3l/land_ice_segments/ground_track/sigma_geo_at',\n", - " 'gt3l/land_ice_segments/ground_track/sigma_geo_r',\n", - " 'gt3l/land_ice_segments/ground_track/sigma_geo_xt',\n", - " 'gt3l/land_ice_segments/ground_track/x_atc',\n", - " 'gt3l/land_ice_segments/ground_track/y_atc',\n", - " 'gt3l/land_ice_segments/h_li',\n", - " 'gt3l/land_ice_segments/h_li_sigma',\n", - " 'gt3l/land_ice_segments/latitude',\n", - " 'gt3l/land_ice_segments/longitude',\n", - " 'gt3l/land_ice_segments/segment_id',\n", - " 'gt3l/land_ice_segments/sigma_geo_h',\n", - " 'gt3l/residual_histogram/bckgrd_per_m',\n", - " 'gt3l/residual_histogram/bin_top_h',\n", - " 'gt3l/residual_histogram/count',\n", - " 'gt3l/residual_histogram/delta_time',\n", - " 'gt3l/residual_histogram/ds_segment_id',\n", - " 'gt3l/residual_histogram/lat_mean',\n", - " 'gt3l/residual_histogram/lon_mean',\n", - " 'gt3l/residual_histogram/pulse_count',\n", - " 'gt3l/residual_histogram/segment_id_list',\n", - " 'gt3l/residual_histogram/x_atc_mean',\n", - " 'gt3l/segment_quality/delta_time',\n", - " 'gt3l/segment_quality/record_number',\n", - " 'gt3l/segment_quality/reference_pt_lat',\n", - " 'gt3l/segment_quality/reference_pt_lon',\n", - " 'gt3l/segment_quality/segment_id',\n", - " 'gt3l/segment_quality/signal_selection_source',\n", - " 'gt3l/segment_quality/signal_selection_status/signal_selection_status_all',\n", - " 'gt3l/segment_quality/signal_selection_status/signal_selection_status_backup',\n", - " 'gt3l/segment_quality/signal_selection_status/signal_selection_status_confident',\n", - " 'gt3r/land_ice_segments/atl06_quality_summary',\n", - " 'gt3r/land_ice_segments/bias_correction/fpb_mean_corr',\n", - " 'gt3r/land_ice_segments/bias_correction/fpb_mean_corr_sigma',\n", - " 'gt3r/land_ice_segments/bias_correction/fpb_med_corr',\n", - " 'gt3r/land_ice_segments/bias_correction/fpb_med_corr_sigma',\n", - " 'gt3r/land_ice_segments/bias_correction/fpb_n_corr',\n", - " 'gt3r/land_ice_segments/bias_correction/med_r_fit',\n", - " 'gt3r/land_ice_segments/bias_correction/tx_mean_corr',\n", - " 'gt3r/land_ice_segments/bias_correction/tx_med_corr',\n", - " 'gt3r/land_ice_segments/delta_time',\n", - " 'gt3r/land_ice_segments/dem/dem_flag',\n", - " 'gt3r/land_ice_segments/dem/dem_h',\n", - " 'gt3r/land_ice_segments/dem/geoid_free2mean',\n", - " 'gt3r/land_ice_segments/dem/geoid_h',\n", - " 'gt3r/land_ice_segments/fit_statistics/dh_fit_dx',\n", - " 'gt3r/land_ice_segments/fit_statistics/dh_fit_dx_sigma',\n", - " 'gt3r/land_ice_segments/fit_statistics/dh_fit_dy',\n", - " 'gt3r/land_ice_segments/fit_statistics/h_expected_rms',\n", - " 'gt3r/land_ice_segments/fit_statistics/h_mean',\n", - " 'gt3r/land_ice_segments/fit_statistics/h_rms_misfit',\n", - " 'gt3r/land_ice_segments/fit_statistics/h_robust_sprd',\n", - " 'gt3r/land_ice_segments/fit_statistics/n_fit_photons',\n", - " 'gt3r/land_ice_segments/fit_statistics/n_seg_pulses',\n", - " 'gt3r/land_ice_segments/fit_statistics/sigma_h_mean',\n", - " 'gt3r/land_ice_segments/fit_statistics/signal_selection_source',\n", - " 'gt3r/land_ice_segments/fit_statistics/signal_selection_source_status',\n", - " 'gt3r/land_ice_segments/fit_statistics/snr',\n", - " 'gt3r/land_ice_segments/fit_statistics/snr_significance',\n", - " 'gt3r/land_ice_segments/fit_statistics/w_surface_window_final',\n", - " 'gt3r/land_ice_segments/geophysical/bckgrd',\n", - " 'gt3r/land_ice_segments/geophysical/bsnow_conf',\n", - " 'gt3r/land_ice_segments/geophysical/bsnow_h',\n", - " 'gt3r/land_ice_segments/geophysical/bsnow_od',\n", - " 'gt3r/land_ice_segments/geophysical/cloud_flg_asr',\n", - " 'gt3r/land_ice_segments/geophysical/cloud_flg_atm',\n", - " 'gt3r/land_ice_segments/geophysical/dac',\n", - " 'gt3r/land_ice_segments/geophysical/e_bckgrd',\n", - " 'gt3r/land_ice_segments/geophysical/layer_flag',\n", - " 'gt3r/land_ice_segments/geophysical/msw_flag',\n", - " 'gt3r/land_ice_segments/geophysical/neutat_delay_total',\n", - " 'gt3r/land_ice_segments/geophysical/r_eff',\n", - " 'gt3r/land_ice_segments/geophysical/solar_azimuth',\n", - " 'gt3r/land_ice_segments/geophysical/solar_elevation',\n", - " 'gt3r/land_ice_segments/geophysical/tide_earth',\n", - " 'gt3r/land_ice_segments/geophysical/tide_earth_free2mean',\n", - " 'gt3r/land_ice_segments/geophysical/tide_equilibrium',\n", - " 'gt3r/land_ice_segments/geophysical/tide_load',\n", - " 'gt3r/land_ice_segments/geophysical/tide_ocean',\n", - " 'gt3r/land_ice_segments/geophysical/tide_pole',\n", - " 'gt3r/land_ice_segments/ground_track/ref_azimuth',\n", - " 'gt3r/land_ice_segments/ground_track/ref_coelv',\n", - " 'gt3r/land_ice_segments/ground_track/seg_azimuth',\n", - " 'gt3r/land_ice_segments/ground_track/sigma_geo_at',\n", - " 'gt3r/land_ice_segments/ground_track/sigma_geo_r',\n", - " 'gt3r/land_ice_segments/ground_track/sigma_geo_xt',\n", - " 'gt3r/land_ice_segments/ground_track/x_atc',\n", - " 'gt3r/land_ice_segments/ground_track/y_atc',\n", - " 'gt3r/land_ice_segments/h_li',\n", - " 'gt3r/land_ice_segments/h_li_sigma',\n", - " 'gt3r/land_ice_segments/latitude',\n", - " 'gt3r/land_ice_segments/longitude',\n", - " 'gt3r/land_ice_segments/segment_id',\n", - " 'gt3r/land_ice_segments/sigma_geo_h',\n", - " 'gt3r/residual_histogram/bckgrd_per_m',\n", - " 'gt3r/residual_histogram/bin_top_h',\n", - " 'gt3r/residual_histogram/count',\n", - " 'gt3r/residual_histogram/delta_time',\n", - " 'gt3r/residual_histogram/ds_segment_id',\n", - " 'gt3r/residual_histogram/lat_mean',\n", - " 'gt3r/residual_histogram/lon_mean',\n", - " 'gt3r/residual_histogram/pulse_count',\n", - " 'gt3r/residual_histogram/segment_id_list',\n", - " 'gt3r/residual_histogram/x_atc_mean',\n", - " 'gt3r/segment_quality/delta_time',\n", - " 'gt3r/segment_quality/record_number',\n", - " 'gt3r/segment_quality/reference_pt_lat',\n", - " 'gt3r/segment_quality/reference_pt_lon',\n", - " 'gt3r/segment_quality/segment_id',\n", - " 'gt3r/segment_quality/signal_selection_source',\n", - " 'gt3r/segment_quality/signal_selection_status/signal_selection_status_all',\n", - " 'gt3r/segment_quality/signal_selection_status/signal_selection_status_backup',\n", - " 'gt3r/segment_quality/signal_selection_status/signal_selection_status_confident',\n", - " 'orbit_info/bounding_polygon_lat1',\n", - " 'orbit_info/bounding_polygon_lon1',\n", - " 'orbit_info/crossing_time',\n", - " 'orbit_info/cycle_number',\n", - " 'orbit_info/lan',\n", - " 'orbit_info/orbit_number',\n", - " 'orbit_info/rgt',\n", - " 'orbit_info/sc_orient',\n", - " 'orbit_info/sc_orient_time',\n", - " 'quality_assessment/gt1l/delta_time',\n", - " 'quality_assessment/gt1l/lat_mean',\n", - " 'quality_assessment/gt1l/lon_mean',\n", - " 'quality_assessment/gt1l/signal_selection_source_fraction_0',\n", - " 'quality_assessment/gt1l/signal_selection_source_fraction_1',\n", - " 'quality_assessment/gt1l/signal_selection_source_fraction_2',\n", - " 'quality_assessment/gt1l/signal_selection_source_fraction_3',\n", - " 'quality_assessment/gt1r/delta_time',\n", - " 'quality_assessment/gt1r/lat_mean',\n", - " 'quality_assessment/gt1r/lon_mean',\n", - " 'quality_assessment/gt1r/signal_selection_source_fraction_0',\n", - " 'quality_assessment/gt1r/signal_selection_source_fraction_1',\n", - " 'quality_assessment/gt1r/signal_selection_source_fraction_2',\n", - " 'quality_assessment/gt1r/signal_selection_source_fraction_3',\n", - " 'quality_assessment/gt2l/delta_time',\n", - " 'quality_assessment/gt2l/lat_mean',\n", - " 'quality_assessment/gt2l/lon_mean',\n", - " 'quality_assessment/gt2l/signal_selection_source_fraction_0',\n", - " 'quality_assessment/gt2l/signal_selection_source_fraction_1',\n", - " 'quality_assessment/gt2l/signal_selection_source_fraction_2',\n", - " 'quality_assessment/gt2l/signal_selection_source_fraction_3',\n", - " 'quality_assessment/gt2r/delta_time',\n", - " 'quality_assessment/gt2r/lat_mean',\n", - " 'quality_assessment/gt2r/lon_mean',\n", - " 'quality_assessment/gt2r/signal_selection_source_fraction_0',\n", - " 'quality_assessment/gt2r/signal_selection_source_fraction_1',\n", - " 'quality_assessment/gt2r/signal_selection_source_fraction_2',\n", - " 'quality_assessment/gt2r/signal_selection_source_fraction_3',\n", - " 'quality_assessment/gt3l/delta_time',\n", - " 'quality_assessment/gt3l/lat_mean',\n", - " 'quality_assessment/gt3l/lon_mean',\n", - " 'quality_assessment/gt3l/signal_selection_source_fraction_0',\n", - " 'quality_assessment/gt3l/signal_selection_source_fraction_1',\n", - " 'quality_assessment/gt3l/signal_selection_source_fraction_2',\n", - " 'quality_assessment/gt3l/signal_selection_source_fraction_3',\n", - " 'quality_assessment/gt3r/delta_time',\n", - " 'quality_assessment/gt3r/lat_mean',\n", - " 'quality_assessment/gt3r/lon_mean',\n", - " 'quality_assessment/gt3r/signal_selection_source_fraction_0',\n", - " 'quality_assessment/gt3r/signal_selection_source_fraction_1',\n", - " 'quality_assessment/gt3r/signal_selection_source_fraction_2',\n", - " 'quality_assessment/gt3r/signal_selection_source_fraction_3',\n", - " 'quality_assessment/qa_granule_fail_reason',\n", - " 'quality_assessment/qa_granule_pass_fail']" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "reader.vars.avail()" ] @@ -1635,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "id": "e3734e09", "metadata": {}, "outputs": [], @@ -1655,44 +391,10 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "id": "e5456e36", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'sc_orient': ['orbit_info/sc_orient'],\n", - " 'atlas_sdp_gps_epoch': ['ancillary_data/atlas_sdp_gps_epoch'],\n", - " 'cycle_number': ['orbit_info/cycle_number'],\n", - " 'rgt': ['orbit_info/rgt'],\n", - " 'data_start_utc': ['ancillary_data/data_start_utc'],\n", - " 'data_end_utc': ['ancillary_data/data_end_utc'],\n", - " 'h_li': ['gt1l/land_ice_segments/h_li',\n", - " 'gt1r/land_ice_segments/h_li',\n", - " 'gt2l/land_ice_segments/h_li',\n", - " 'gt2r/land_ice_segments/h_li',\n", - " 'gt3l/land_ice_segments/h_li',\n", - " 'gt3r/land_ice_segments/h_li'],\n", - " 'latitude': ['gt1l/land_ice_segments/latitude',\n", - " 'gt1r/land_ice_segments/latitude',\n", - " 'gt2l/land_ice_segments/latitude',\n", - " 'gt2r/land_ice_segments/latitude',\n", - " 'gt3l/land_ice_segments/latitude',\n", - " 'gt3r/land_ice_segments/latitude'],\n", - " 'longitude': ['gt1l/land_ice_segments/longitude',\n", - " 'gt1r/land_ice_segments/longitude',\n", - " 'gt2l/land_ice_segments/longitude',\n", - " 'gt2r/land_ice_segments/longitude',\n", - " 'gt3l/land_ice_segments/longitude',\n", - " 'gt3r/land_ice_segments/longitude']}" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "reader.vars.wanted" ] @@ -1709,7 +411,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "id": "69894391", "metadata": {}, "outputs": [], @@ -1739,113 +441,10 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "id": "eaabc976", "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:49: UserWarning: Converting non-nanosecond precision datetime values to nanosecond precision. This behavior can eventually be relaxed in xarray, as it is an artifact from pandas which is now beginning to support non-nanosecond precision values. This warning is caused by passing non-nanosecond np.datetime64 or np.timedelta64 values to the DataArray or Variable constructor; it can be silenced by converting the values to nanosecond precision ahead of time.\n", - " df.update({keyword: df[keyword].str[:-1].astype(np.datetime64)})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n", - "/home/jovyan/envs/general/lib/python3.11/site-packages/icepyx/core/read.py:490: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n", - " .rename({\"delta_time\": \"photon_idx\"})\n" - ] - } - ], + "outputs": [], "source": [ "ds = reader.load()" ] @@ -1866,549 +465,10 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "id": "723256f7", "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "
<xarray.Dataset>\n",
-       "Dimensions:              (photon_idx: 29027, spot: 2, gran_idx: 6)\n",
-       "Coordinates:\n",
-       "  * photon_idx           (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n",
-       "  * spot                 (spot) uint8 2 5\n",
-       "  * gran_idx             (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n",
-       "    source_file          (gran_idx) <U72 '../../../../data/ATL06/processed_AT...\n",
-       "    delta_time           (gran_idx, photon_idx) datetime64[ns] 2019-02-22T01:...\n",
-       "Data variables:\n",
-       "    sc_orient            (gran_idx) int8 0 0 0 1 1 1\n",
-       "    cycle_number         (gran_idx) int8 2 2 2 5 5 5\n",
-       "    rgt                  (gran_idx) int16 849 902 910 986 1001 1016\n",
-       "    atlas_sdp_gps_epoch  (gran_idx) datetime64[ns] 2018-01-01T00:00:18 ... 20...\n",
-       "    data_start_utc       (gran_idx) datetime64[ns] 2019-02-22T01:03:44.199777...\n",
-       "    data_end_utc         (gran_idx) datetime64[ns] 2019-02-22T01:07:38.112326...\n",
-       "    h_li                 (spot, gran_idx, photon_idx) float32 nan nan ... nan\n",
-       "    latitude             (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
-       "    longitude            (spot, gran_idx, photon_idx) float64 nan nan ... nan\n",
-       "    gt                   (gran_idx, spot) <U4 'gt3r' 'gt1l' ... 'gt1l' 'gt3r'\n",
-       "Attributes:\n",
-       "    data_product:  ATL06\n",
-       "    Description:   The land_ice_height group contains the primary set of deri...\n",
-       "    data_rate:     Data within this group are sparse.  Data values are provid...
" - ], - "text/plain": [ - "\n", - "Dimensions: (photon_idx: 29027, spot: 2, gran_idx: 6)\n", - "Coordinates:\n", - " * photon_idx (photon_idx) int64 0 1 2 3 ... 29023 29024 29025 29026\n", - " * spot (spot) uint8 2 5\n", - " * gran_idx (gran_idx) float64 8.49e+04 9.02e+04 ... 1.016e+05\n", - " source_file (gran_idx) " - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "ds.plot.scatter(x=\"longitude\", y=\"latitude\", hue=\"h_li\", vmin=-100, vmax=2000)" ] From b26ca4eb0ed54cf075bf6c53f31cd78114e5c182 Mon Sep 17 00:00:00 2001 From: Rachel Wegener <35503632+rwegener2@users.noreply.github.com> Date: Fri, 1 Sep 2023 13:38:37 -0400 Subject: [PATCH 10/30] Update icepyx/core/read.py Co-authored-by: Wei Ji <23487320+weiji14@users.noreply.github.com> --- icepyx/core/read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index d3ca0d82a..2ffe32cb7 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -680,7 +680,7 @@ def _build_dataset_template(self, file): def _read_single_grp(self, file, grp_path): """ - For a given file and variable group path, construct an an xarray Dataset. + For a given file and variable group path, construct an xarray Dataset. Parameters ---------- From ce1ca76b7e2d586eaba3695308fae0e0bcd4805f Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Fri, 1 Sep 2023 17:40:10 +0000 Subject: [PATCH 11/30] remove intake and related modules --- requirements.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index 86618f108..06f4ad9a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,8 +7,6 @@ h5netcdf h5py holoviews hvplot -intake -intake-xarray matplotlib numpy requests From 431af78cd55d51fd08881e440d1a55681816db5b Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 5 Sep 2023 16:27:50 +0000 Subject: [PATCH 12/30] mvp with new read parameters --- icepyx/core/read.py | 114 +++++++++++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 39 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 2ffe32cb7..c15957210 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -1,11 +1,14 @@ import fnmatch +import glob import os import warnings +import h5py import numpy as np import xarray as xr import icepyx.core.is2ref as is2ref +from icepyx.core.query import Query from icepyx.core.variables import Variables as Variables from icepyx.core.variables import list_of_dict_vals @@ -297,56 +300,79 @@ class Read: def __init__( self, - data_source=None, + path, # TODO how to deal with the fact that this is required in later versions + # but does not exist in past versions? + out_obj_type=None, # xr.Dataset, product=None, + data_source=None, filename_pattern="ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5", - out_obj_type=None, # xr.Dataset, ): - if data_source is None: - raise ValueError("Please provide a data source.") - else: - self._source_type = _check_datasource(data_source) - self.data_source = data_source - - if product is None: - raise ValueError( - "Please provide the ICESat-2 data product of your file(s)." - ) - else: - self._prod = is2ref._validate_product(product) - pattern_ck, filelist = Read._check_source_for_pattern( - data_source, filename_pattern - ) - assert pattern_ck - # Note: need to check if this works for subset and non-subset NSIDC files (processed_ prepends the former) - self._pattern = filename_pattern - - # this is a first pass at getting rid of mixed product types and warning the user. - # it takes an approach assuming the product name is in the filename, but needs reworking if we let multiple products be loaded - # one way to handle this would be bring in the product info during the loading step and fill in product there instead of requiring it from the user - filtered_filelist = [file for file in filelist if self._prod in file] - if len(filtered_filelist) == 0: - warnings.warn( - "Your filenames do not contain a product identifier (e.g. ATL06). " - "You will likely need to manually merge your dataframes." - ) - self._filelist = filelist - elif len(filtered_filelist) < len(filelist): - warnings.warn( - "Some files matching your filename pattern were removed as they were not the specified product." - ) - self._filelist = filtered_filelist + # Raise warnings for depreciated arguments + if data_source: + warnings.warn('The `data_source` argument is depreciated. Please use the path argument instead.') + # TODO this check doesn't work because default isn't None + if filename_pattern: + warnings.warn('The `filename_pattern` argument is depreciated. Instead please provide a glob string to the `path` argument') + + # CREATE THE FILELIST + # Create the filelist from the user `path` argument + if isinstance(path, list): + self._filelist = path + # Discussion: I think actually this parameter type will only exist for cloud? + # Unless we really want to abstract more stuff, i.e. the downloading + # elif isinstance(path, Query): + # self._filelist = path. + elif os.path.isdir(path): + path = os.path.join(path, '*') + # TODO better flow so ths glob doesn't happen twice + self._filelist = glob.glob(path) else: - self._filelist = filelist - + # Discussion: should we default to recursive or not? + # Could allow for glob kwargs, but at that point I think we should just tell + # the user to run glob themself to create the filelist. + self._filelist = glob.glob(path) + + # EXTRACT THE PRODUCT FOR EACH FILE + # Note for ticket: this logic got a little complex in the attempt to maintain a + # user-given product argument. If this gets depreciated we could depricate this + # Create a dictionary of the metadata extracted + product_dict = {} + for file_ in self._filelist: + product_dict[file_] = self._extract_product(file_) + # DEAL WITH MULTIPLE PRODUCTS IN THE LIST + # raise warning if there are multiple products present + if len(set(product_dict.values())) > 1: + # filter to only one product + if product: + warnings.warn(f'Multiple products found in list of files: {product_dict}. Files that do not match the user specified product will be removed from processing.') + # TODO thoughts on making filelist public read-only? It seems fair as I write + # all these warnings/error messages that reference a filelist. + self._filelist = [] + for key, value in product_dict.items(): + if value == product: + self._filelist.append(key) + product_dict.pop(key) + if len(self._filelist) == 0: + raise 'No files found in the file list matching the user-specified product type' + else: + raise TypeError(f'Multiple product types were found in the file list: {product_dict}. Please provide a valid `path` parameter indicating files of a single product') + # ASSIGN A PRODUCT TO THIS FILELIST + self.product = list(product_dict.values())[0] + if product and self.product != product: + warnings.warn(f'User specified product {product} does not match the product from the file metadata {self.product}') + + # Discussion: is this code meaningful to others? or can it be cleaned up? # after validation, use the notebook code and code outline to start implementing the rest of the class - + if out_obj_type is not None: print( "Output object type will be an xarray DataSet - " "no other output types are implemented yet" ) self._out_obj = xr.Dataset + + print('filelist:', self._filelist) + print('product', self.product) # ---------------------------------------------------------------------- # Properties @@ -379,6 +405,16 @@ def vars(self): # ---------------------------------------------------------------------- # Methods + + @staticmethod + def _extract_product(filepath): + with h5py.File(filepath, 'r') as f: + try: + product = f['METADATA']['DatasetIdentification'].attrs['shortName'].decode() + # TODO test that this is the proper error + except KeyError: + raise 'Unable to parse the product name from file metadata' + return product @staticmethod def _check_source_for_pattern(source, filename_pattern): From 612662e3ffc9395bc90557c4fdaba0a88500b068 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 5 Sep 2023 17:45:54 +0000 Subject: [PATCH 13/30] clean up remainder of file and remove extraneous comments --- icepyx/core/read.py | 137 +++++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 54 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index c15957210..c8fe4f276 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -300,69 +300,83 @@ class Read: def __init__( self, - path, # TODO how to deal with the fact that this is required in later versions - # but does not exist in past versions? - out_obj_type=None, # xr.Dataset, + path=None, product=None, data_source=None, filename_pattern="ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5", + out_obj_type=None, # xr.Dataset, ): # Raise warnings for depreciated arguments if data_source: - warnings.warn('The `data_source` argument is depreciated. Please use the path argument instead.') - # TODO this check doesn't work because default isn't None - if filename_pattern: - warnings.warn('The `filename_pattern` argument is depreciated. Instead please provide a glob string to the `path` argument') + warnings.warn( + 'The `data_source` argument is depreciated. Please use the path argument ' + 'instead.' + ) + if filename_pattern != "ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5": + warnings.warn( + 'The `filename_pattern` argument is depreciated. Instead please provide a ' + 'glob string to the `path` argument' + ) + if product: + product = is2ref._validate_product(product) + warnings.warn( + 'The `product` argument is no longer required. If the `path` argument given ' + 'contains files with multiple products the `product` argument will be used ' + 'to filter that list. In all other cases the product argument is ignored. ' + 'The recommended approach is to not include a `product` argument and instead ' + 'provide a `path` with files of only a single product type`.' + ) - # CREATE THE FILELIST # Create the filelist from the user `path` argument if isinstance(path, list): self._filelist = path - # Discussion: I think actually this parameter type will only exist for cloud? - # Unless we really want to abstract more stuff, i.e. the downloading - # elif isinstance(path, Query): - # self._filelist = path. elif os.path.isdir(path): path = os.path.join(path, '*') - # TODO better flow so ths glob doesn't happen twice self._filelist = glob.glob(path) else: - # Discussion: should we default to recursive or not? - # Could allow for glob kwargs, but at that point I think we should just tell - # the user to run glob themself to create the filelist. self._filelist = glob.glob(path) + # Remove any directories from the list + self._filelist = [f for f in self._filelist if not os.path.isdir(f)] - # EXTRACT THE PRODUCT FOR EACH FILE - # Note for ticket: this logic got a little complex in the attempt to maintain a - # user-given product argument. If this gets depreciated we could depricate this - # Create a dictionary of the metadata extracted + # Create a dictionary of the products as read from the metadata product_dict = {} for file_ in self._filelist: product_dict[file_] = self._extract_product(file_) - # DEAL WITH MULTIPLE PRODUCTS IN THE LIST - # raise warning if there are multiple products present - if len(set(product_dict.values())) > 1: - # filter to only one product + + # Raise warnings or errors for muliple products or products not matching the user-specified product + all_products = list(set(product_dict.values())) + if len(all_products) > 1: if product: - warnings.warn(f'Multiple products found in list of files: {product_dict}. Files that do not match the user specified product will be removed from processing.') - # TODO thoughts on making filelist public read-only? It seems fair as I write - # all these warnings/error messages that reference a filelist. + warnings.warn( + f'Multiple products found in list of files: {product_dict}. Files that ' + 'do not match the user specified product will be removed from processing.' + ) self._filelist = [] for key, value in product_dict.items(): if value == product: self._filelist.append(key) - product_dict.pop(key) if len(self._filelist) == 0: - raise 'No files found in the file list matching the user-specified product type' + raise TypeError( + 'No files found in the file list matching the user-specified ' + 'product type' + ) + # Use the cleaned filelist to assign a product + self._product = product else: - raise TypeError(f'Multiple product types were found in the file list: {product_dict}. Please provide a valid `path` parameter indicating files of a single product') - # ASSIGN A PRODUCT TO THIS FILELIST - self.product = list(product_dict.values())[0] - if product and self.product != product: - warnings.warn(f'User specified product {product} does not match the product from the file metadata {self.product}') - - # Discussion: is this code meaningful to others? or can it be cleaned up? - # after validation, use the notebook code and code outline to start implementing the rest of the class + raise TypeError( + f'Multiple product types were found in the file list: {product_dict}.' + 'Please provide a valid `path` parameter indicating files of a single ' + 'product' + ) + else: + # Assign the identified product to the property + self._product = all_products[0] + # Raise a warning if the metadata-located product differs from the user-specified product + if product and self._product != product: + warnings.warn( + f'User specified product {product} does not match the product from the file' + ' metadata {self._product}' + ) if out_obj_type is not None: print( @@ -370,9 +384,6 @@ def __init__( "no other output types are implemented yet" ) self._out_obj = xr.Dataset - - print('filelist:', self._filelist) - print('product', self.product) # ---------------------------------------------------------------------- # Properties @@ -398,18 +409,45 @@ def vars(self): if not hasattr(self, "_read_vars"): self._read_vars = Variables( - "file", path=self._filelist[0], product=self._prod + "file", path=self.filelist[0], product=self.product ) return self._read_vars + + @property + def filelist(self): + """ + A read-only property for the user to view the list of files represented by this + Read object. + """ + return self._filelist + + @property + def num_files(self): + """ + Return the number of files that is being processed by the object + """ + return len(self.filelist) + + @property + def product(self): + """ + A read-only property for the user to view the product associated with the Read + object. + """ + return self._product # ---------------------------------------------------------------------- # Methods @staticmethod def _extract_product(filepath): + """ + Read the product type from the metadata of the file. Return the product as a string. + """ with h5py.File(filepath, 'r') as f: try: + # TODO consider: should we get this from the top level attrs instead? product = f['METADATA']['DatasetIdentification'].attrs['shortName'].decode() # TODO test that this is the proper error except KeyError: @@ -675,7 +713,7 @@ def load(self): # However, this led to errors when I tried to combine two identical datasets because the single dimension was equal. # In these situations, xarray recommends manually controlling the merge/concat process yourself. # While unlikely to be a broad issue, I've heard of multiple matching timestamps causing issues for combining multiple IS2 datasets. - for file in self._filelist: + for file in self.filelist: all_dss.append( self._build_single_file_dataset(file, groups_list) ) # wanted_groups, vgrp.keys())) @@ -710,7 +748,7 @@ def _build_dataset_template(self, file): gran_idx=[np.uint64(999999)], source_file=(["gran_idx"], [file]), ), - attrs=dict(data_product=self._prod), + attrs=dict(data_product=self.product), ) return is2ds @@ -754,20 +792,11 @@ def _build_single_file_dataset(self, file, groups_list): ------- Xarray Dataset """ - file_product = self._read_single_grp(file, "/").attrs["identifier_product_type"] - assert ( - file_product == self._prod - ), "Your product specification does not match the product specification within your files." - # I think the below method might NOT read the file into memory as the above might? - # import h5py - # with h5py.File(filepath,'r') as h5pt: - # prod_id = h5pt.attrs["identifier_product_type"] - # DEVNOTE: if and elif does not actually apply wanted variable list, and has not been tested for merging multiple files into one ds # if a gridded product # TODO: all products need to be tested, and quicklook products added or explicitly excluded # Level 3b, gridded (netcdf): ATL14, 15, 16, 17, 18, 19, 20, 21 - if self._prod in [ + if self.product in [ "ATL14", "ATL15", "ATL16", @@ -780,7 +809,7 @@ def _build_single_file_dataset(self, file, groups_list): is2ds = xr.open_dataset(file) # Level 3b, hdf5: ATL11 - elif self._prod in ["ATL11"]: + elif self.product in ["ATL11"]: is2ds = self._build_dataset_template(file) # returns the wanted groups as a single list of full group path strings From c16a00359034b5920780ce0f7719ea6c9000891d Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 5 Sep 2023 21:06:39 +0000 Subject: [PATCH 14/30] maintain backward compatibility and combine arguments --- icepyx/core/is2ref.py | 5 +++-- icepyx/core/read.py | 51 +++++++++++++++++++++++-------------------- 2 files changed, 30 insertions(+), 26 deletions(-) diff --git a/icepyx/core/is2ref.py b/icepyx/core/is2ref.py index 883772a9e..6003d91b8 100644 --- a/icepyx/core/is2ref.py +++ b/icepyx/core/is2ref.py @@ -15,6 +15,7 @@ def _validate_product(product): """ Confirm a valid ICESat-2 product was specified """ + error_msg = "A valid product string was not provided. Check user input, if given, or file metadata." if isinstance(product, str): product = str.upper(product) assert product in [ @@ -39,9 +40,9 @@ def _validate_product(product): "ATL19", "ATL20", "ATL21", - ], "Please enter a valid product" + ], error_msg else: - raise TypeError("Please enter a product string") + raise TypeError(error_msg) return product diff --git a/icepyx/core/read.py b/icepyx/core/read.py index c8fe4f276..c900ed6c4 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -297,26 +297,23 @@ class Read: # ---------------------------------------------------------------------- # Constructors - + + # TODO -- update docstring + def __init__( self, - path=None, + data_source, product=None, - data_source=None, - filename_pattern="ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5", + filename_pattern=None, out_obj_type=None, # xr.Dataset, ): # Raise warnings for depreciated arguments - if data_source: - warnings.warn( - 'The `data_source` argument is depreciated. Please use the path argument ' - 'instead.' - ) - if filename_pattern != "ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5": + if filename_pattern: warnings.warn( 'The `filename_pattern` argument is depreciated. Instead please provide a ' - 'glob string to the `path` argument' + 'string, list, or glob string to the `data_source` argument.' ) + if product: product = is2ref._validate_product(product) warnings.warn( @@ -327,14 +324,21 @@ def __init__( 'provide a `path` with files of only a single product type`.' ) - # Create the filelist from the user `path` argument - if isinstance(path, list): - self._filelist = path - elif os.path.isdir(path): - path = os.path.join(path, '*') - self._filelist = glob.glob(path) + # Create the filelist from the `data_source` argument + if filename_pattern: + # maintained for backward compatibility + pattern_ck, filelist = Read._check_source_for_pattern( + data_source, filename_pattern + ) + assert pattern_ck + self._filelist = filelist + elif isinstance(data_source, list): + self._filelist = data_source + elif os.path.isdir(data_source): + data_source = os.path.join(data_source, '*') + self._filelist = glob.glob(data_source) else: - self._filelist = glob.glob(path) + self._filelist = glob.glob(data_source) # Remove any directories from the list self._filelist = [f for f in self._filelist if not os.path.isdir(f)] @@ -342,7 +346,7 @@ def __init__( product_dict = {} for file_ in self._filelist: product_dict[file_] = self._extract_product(file_) - + # Raise warnings or errors for muliple products or products not matching the user-specified product all_products = list(set(product_dict.values())) if len(all_products) > 1: @@ -417,23 +421,21 @@ def vars(self): @property def filelist(self): """ - A read-only property for the user to view the list of files represented by this - Read object. + A read-only property for viewing the list of files represented by this Read object. """ return self._filelist @property def num_files(self): """ - Return the number of files that is being processed by the object + Return the number of files that are being processed """ return len(self.filelist) @property def product(self): """ - A read-only property for the user to view the product associated with the Read - object. + A read-only property for the user to view the product associated with the Read object. """ return self._product @@ -449,6 +451,7 @@ def _extract_product(filepath): try: # TODO consider: should we get this from the top level attrs instead? product = f['METADATA']['DatasetIdentification'].attrs['shortName'].decode() + product = is2ref._validate_product(product) # TODO test that this is the proper error except KeyError: raise 'Unable to parse the product name from file metadata' From 76480783444165519b66590b31e99248b27ad35b Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 5 Sep 2023 22:15:31 +0000 Subject: [PATCH 15/30] update to new error message --- icepyx/tests/test_is2ref.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/icepyx/tests/test_is2ref.py b/icepyx/tests/test_is2ref.py index c2ddf6e5e..7d1bba7bf 100644 --- a/icepyx/tests/test_is2ref.py +++ b/icepyx/tests/test_is2ref.py @@ -8,14 +8,14 @@ def test_num_product(): dsnum = 6 - ermsg = "Please enter a product string" + ermsg = "A valid product string was not provided. Check user input, if given, or file metadata." with pytest.raises(TypeError, match=ermsg): is2ref._validate_product(dsnum) def test_bad_product(): wrngds = "atl-6" - ermsg = "Please enter a valid product" + ermsg = "A valid product string was not provided. Check user input, if given, or file metadata." with pytest.raises(AssertionError, match=ermsg): is2ref._validate_product(wrngds) From 4cfbfdbd7cda2701ab3036cd381cd16f7f889c6c Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Fri, 8 Sep 2023 14:16:25 +0000 Subject: [PATCH 16/30] update docs --- .../example_notebooks/IS2_data_read-in.ipynb | 180 +++++++++++++----- doc/source/user_guide/documentation/read.rst | 3 + icepyx/core/read.py | 44 +++-- 3 files changed, 165 insertions(+), 62 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index 115c63044..9288e7da3 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -63,9 +63,8 @@ "metadata": {}, "outputs": [], "source": [ - "path_root = '/full/path/to/your/data/'\n", - "pattern = \"processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"\n", - "reader = ipx.Read(path_root, \"ATL06\", pattern) # or ipx.Read(filepath, \"ATLXX\") if your filenames match the default pattern" + "path_root = '/full/path/to/your/ATL06_data/'\n", + "reader = ipx.Read(path_root)" ] }, { @@ -111,10 +110,9 @@ "\n", "Reading in ICESat-2 data with icepyx happens in a few simple steps:\n", "1. Let icepyx know where to find your data (this might be local files or urls to data in cloud storage)\n", - "2. Tell icepyx how to interpret the filename format\n", - "3. Create an icepyx `Read` object\n", - "4. Make a list of the variables you want to read in (does not apply for gridded products)\n", - "5. Load your data into memory (or read it in lazily, if you're using Dask)\n", + "2. Create an icepyx `Read` object\n", + "3. Make a list of the variables you want to read in (does not apply for gridded products)\n", + "4. Load your data into memory (or read it in lazily, if you're using Dask)\n", "\n", "We go through each of these steps in more detail in this notebook." ] @@ -168,17 +166,18 @@ { "cell_type": "markdown", "id": "e8da42c1", - "metadata": {}, + "metadata": { + "user_expressions": [] + }, "source": [ "### Step 1: Set data source path\n", "\n", "Provide a full path to the data to be read in (i.e. opened).\n", "Currently accepted inputs are:\n", - "* a directory\n", - "* a single file\n", - "\n", - "All files to be read in *must* have a consistent filename pattern.\n", - "If a directory is supplied as the data source, all files in any subdirectories that match the filename pattern will be included.\n", + "* a string path to directory - all files from the directory will be opened\n", + "* a string path to single file - one file will be opened\n", + "* a list of filepaths - all files in the list will be opened\n", + "* a glob string (see [glob](https://docs.python.org/3/library/glob.html)) - any files matching the glob pattern will be opened\n", "\n", "S3 bucket data access is currently under development, and requires you are registered with NSIDC as a beta tester for cloud-based ICESat-2 data.\n", "icepyx is working to ensure a smooth transition to working with remote files.\n", @@ -205,6 +204,17 @@ "# filepath = path_root + 'ATL06-20181214041627-Sample.h5'" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "fac636c2-e0eb-4e08-adaa-8f47623e46a1", + "metadata": {}, + "outputs": [], + "source": [ + "# list_of_files = ['/my/data/ATL06/processed_ATL06_20190226005526_09100205_006_02.h5', \n", + "# '/my/other/data/ATL06/processed_ATL06_20191202102922_10160505_006_01.h5']" + ] + }, { "cell_type": "code", "execution_count": null, @@ -217,77 +227,123 @@ }, { "cell_type": "markdown", - "id": "92743496", + "id": "ba3ebeb0-3091-4712-b0f7-559ddb95ca5a", "metadata": { "user_expressions": [] }, "source": [ - "### Step 2: Create a filename pattern for your data files\n", + "#### Glob Strings\n", + "\n", + "[glob](https://docs.python.org/3/library/glob.html) is a Python library which allows users to list files in their file systems whose paths match a given pattern. Icepyx uses the glob library to give users greater flexibility over their input file lists.\n", "\n", - "Files provided by NSIDC typically match the format `\"ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"` where the parameters in curly brackets indicate a parameter name (left of the colon) and character length or format (right of the colon).\n", - "Some of this information is used during data opening to help correctly read and label the data within the data structure, particularly when multiple files are opened simultaneously.\n", + "glob works using `*` and `?` as wildcard characters, where `*` matches any number of characters and `?` matches a single character. For example:\n", "\n", - "By default, icepyx will assume your filenames follow the default format.\n", - "However, you can easily read in other ICESat-2 data files by supplying your own filename pattern.\n", - "For instance, `pattern=\"ATL{product:2}-{datetime:%Y%m%d%H%M%S}-Sample.h5\"`. A few example patterns are provided below." + "* `/this/path/*.h5`: refers to all files `.h5` files in the `/this/path` folder\n", + "* `ATL??.h5`: refers to any `.h5` file that starts with `ATL` and then has any 2 characters after it\n", + "* `/this/path/ATL??/*.h5`: refers to all `.h5` files that are in a subfolder of `/this/path` which has a filename of `ATL` followed by any 2 characters\n", + "\n", + "See the glob documentation or other online explainer tutorials for more in depth explanation, or advanced glob paths such as character classes and ranges." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "7318abd0", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "20286c76-5632-4420-b2c9-a5a6b1952672", + "metadata": { + "user_expressions": [] + }, "source": [ - "# pattern = 'ATL06-{datetime:%Y%m%d%H%M%S}-Sample.h5'\n", - "# pattern = 'ATL{product:2}-{datetime:%Y%m%d%H%M%S}-Sample.h5'" + "#### Recursive Directory Search" + ] + }, + { + "cell_type": "markdown", + "id": "632bd1ce-2397-4707-a63f-9d5d2fc02fbc", + "metadata": { + "user_expressions": [] + }, + "source": [ + "If specifying a directory, glob will not by default search all of the subdirectories for matching filepaths. If this is the search method you would like, you can achieve this by either:\n", + "1. passing the `recursive` argument into `glob_kwargs`\n", + "2. using glob directly to create a list of filepaths" + ] + }, + { + "cell_type": "markdown", + "id": "da0cacd8-9ddc-4c31-86b6-167d850b989e", + "metadata": { + "user_expressions": [] + }, + "source": [ + "Method 1: passing the `recursive` argument into `glob_kwargs`" ] }, { "cell_type": "code", "execution_count": null, - "id": "f43e8664", + "id": "be79b0dd-efcf-4d50-bdb0-8e3ae8e8e38c", "metadata": {}, "outputs": [], "source": [ - "# pattern = \"ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"" + "import glob" ] }, { "cell_type": "code", "execution_count": null, - "id": "992a77fb", - "metadata": {}, + "id": "5d088571-496d-479a-9fb7-833ed7e98676", + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "# grid_pattern = \"ATL{product:2}_GL_0311_{res:3}m_{version:3}_{revision:2}.nc\"" + "list_of_files = glob.glob('/path/to/my/folder', recursive=True)\n", + "ipx.Read(list_of_files)" + ] + }, + { + "cell_type": "markdown", + "id": "76de9539-710c-49f6-9e9e-238849382c33", + "metadata": { + "user_expressions": [] + }, + "source": [ + "Method 2: using glob directly to create a list of filepaths" ] }, { "cell_type": "code", "execution_count": null, - "id": "6aec1a70", + "id": "e276b876-9ec7-4991-8520-05c97824b896", "metadata": {}, "outputs": [], "source": [ - "pattern = \"processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"" + "ipx.Read('/path/to/my/folder', glob_kwargs={'recursive': True})" ] }, { "cell_type": "markdown", - "id": "4275b04c", + "id": "08df2874-7c54-4670-8f37-9135ea296ff5", "metadata": { "user_expressions": [] }, "source": [ - "### Step 3: Create an icepyx read object\n", + "```{admonition} Read Module Update\n", + "Previously, icepyx required two additional things: 1) that you specify a `product` and 2) that your files either matched the default `filename_pattern` or that the user provided their own `filename_pattern`. These two requirements have been removed. `product` is not read directly from the file metadata (the root group's `short_name` attribute). Flexibility to specify multiple files via the `filename_pattern` has been replaced with [glob string](https://docs.python.org/3/library/glob.html) and allowing a list of filepaths as an argument.\n", "\n", - "The `Read` object has two required inputs:\n", - "- `path` = a string with the full file path or full directory path to your hdf5 (.h5) format files.\n", - "- `product` = the data product you're working with, also known as the \"short name\".\n", + "These arguments have been maintained for backward compatibility, but will be fully removed in icepyx version 1.0.0.\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "4275b04c", + "metadata": { + "user_expressions": [] + }, + "source": [ + "### Step 2: Create an icepyx read object\n", "\n", - "The `Read` object also accepts the optional keyword input:\n", - "- `pattern` = a formatted string indicating the filename pattern required for Intake's path_as_pattern argument." + "Using the `data_source` described in Step 1, we can create our Read object." ] }, { @@ -299,7 +355,17 @@ }, "outputs": [], "source": [ - "reader = ipx.Read(data_source=path_root, product=\"ATL06\", filename_pattern=pattern) # or ipx.Read(filepath, \"ATLXX\") if your filenames match the default pattern" + "reader = ipx.Read(data_source=path_root)" + ] + }, + { + "cell_type": "markdown", + "id": "7b2acfdb-75eb-4c64-b583-2ab19326aaee", + "metadata": { + "user_expressions": [] + }, + "source": [ + "The Read object now contains the list of matching files that will eventually be loaded into Python. You can inspect its properties, such as the files that were located or the identified product, directly on the Read object." ] }, { @@ -309,7 +375,27 @@ "metadata": {}, "outputs": [], "source": [ - "reader._filelist" + "reader.filelist" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "248590ba-b468-4ca5-999f-4323b704008e", + "metadata": {}, + "outputs": [], + "source": [ + "reader.num_files" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7455ee3f-f9ab-486e-b4c7-2fa2314d4084", + "metadata": {}, + "outputs": [], + "source": [ + "reader.product" ] }, { @@ -319,7 +405,7 @@ "user_expressions": [] }, "source": [ - "### Step 4: Specify variables to be read in\n", + "### Step 3: Specify variables to be read in\n", "\n", "To load your data into memory or prepare it for analysis, icepyx needs to know which variables you'd like to read in.\n", "If you've used icepyx to download data from NSIDC with variable subsetting (which is the default), then you may already be familiar with the icepyx `Variables` module and how to create and modify lists of variables.\n", @@ -426,7 +512,7 @@ "user_expressions": [] }, "source": [ - "### Step 5: Loading your data\n", + "### Step 4: Loading your data\n", "\n", "Now that you've set up all the options, you're ready to read your ICESat-2 data into memory!" ] @@ -541,9 +627,9 @@ ], "metadata": { "kernelspec": { - "display_name": "general", + "display_name": "icepyx-dev", "language": "python", - "name": "general" + "name": "icepyx-dev" }, "language_info": { "codemirror_mode": { diff --git a/doc/source/user_guide/documentation/read.rst b/doc/source/user_guide/documentation/read.rst index a5beedf4e..892f98087 100644 --- a/doc/source/user_guide/documentation/read.rst +++ b/doc/source/user_guide/documentation/read.rst @@ -19,6 +19,9 @@ Attributes .. autosummary:: :toctree: ../../_icepyx/ + Read.filelist + Read.num_files + Read.product Read.vars diff --git a/icepyx/core/read.py b/icepyx/core/read.py index c900ed6c4..90bc6be9d 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -8,12 +8,9 @@ import xarray as xr import icepyx.core.is2ref as is2ref -from icepyx.core.query import Query from icepyx.core.variables import Variables as Variables from icepyx.core.variables import list_of_dict_vals -# from icepyx.core.query import Query - def _make_np_datetime(df, keyword): """ @@ -267,19 +264,19 @@ class Read: Parameters ---------- - data_source : string - A string with a full file path or full directory path to ICESat-2 hdf5 (.h5) format files. - Files within a directory must have a consistent filename pattern that includes the "ATL??" data product name. - Files must all be within a single directory. + data_source : string, List + A string or list which specifies the files to be read. The string can be either: 1) the path of a single file 2) the path to a directory or 3) a [glob string](https://docs.python.org/3/library/glob.html). product : string ICESat-2 data product ID, also known as "short name" (e.g. ATL03). Available data products can be found at: https://nsidc.org/data/icesat-2/data-sets + **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. The dataset product is read from the file metadata. filename_pattern : string, default 'ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5' String that shows the filename pattern as required for Intake's path_as_pattern argument. The default describes files downloaded directly from NSIDC (subsetted and non-subsetted) for most products (e.g. ATL06). The ATL11 filename pattern from NSIDC is: 'ATL{product:2}_{rgt:4}{orbitsegment:2}_{cycles:4}_{version:3}_{revision:2}.h5'. + **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. out_obj_type : object, default xarray.Dataset The desired format for the data to be read in. @@ -292,13 +289,31 @@ class Read: Examples -------- + Reading a single file + ``` + ipx.Read('/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5') # doctest: +SKIP + ``` + Reading all files in a directory + ``` + ipx.Read('/path/to/data/') # doctest: +SKIP + ``` + Reading files that match a particular pattern (here, all .h5 files that start with `processed_ATL06_`). + ``` + ipx.Read('/path/to/data/processed_ATL06_*.h5') # doctest: +SKIP + ``` + Reading a specific list of files + ``` + list_of_files = ['/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', + '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5'] + ipx.Read(list_of_files) # doctest: +SKIP + ``` """ # ---------------------------------------------------------------------- # Constructors - # TODO -- update docstring + # TODO -- what if user passes an empty list, or the glob string returns empty def __init__( self, @@ -317,11 +332,11 @@ def __init__( if product: product = is2ref._validate_product(product) warnings.warn( - 'The `product` argument is no longer required. If the `path` argument given ' + 'The `product` argument is no longer required. If the `data_source` argument given ' 'contains files with multiple products the `product` argument will be used ' 'to filter that list. In all other cases the product argument is ignored. ' 'The recommended approach is to not include a `product` argument and instead ' - 'provide a `path` with files of only a single product type`.' + 'provide a `data_source` with files of only a single product type`.' ) # Create the filelist from the `data_source` argument @@ -369,7 +384,7 @@ def __init__( else: raise TypeError( f'Multiple product types were found in the file list: {product_dict}.' - 'Please provide a valid `path` parameter indicating files of a single ' + 'Please provide a valid `data_source` parameter indicating files of a single ' 'product' ) else: @@ -448,15 +463,14 @@ def _extract_product(filepath): Read the product type from the metadata of the file. Return the product as a string. """ with h5py.File(filepath, 'r') as f: - try: - # TODO consider: should we get this from the top level attrs instead? - product = f['METADATA']['DatasetIdentification'].attrs['shortName'].decode() + try: + product = f.attrs['short_name'].decode() product = is2ref._validate_product(product) # TODO test that this is the proper error except KeyError: raise 'Unable to parse the product name from file metadata' return product - + @staticmethod def _check_source_for_pattern(source, filename_pattern): """ From f7f823b40674fee5e83329d34518403ae285a81f Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Fri, 8 Sep 2023 14:32:45 +0000 Subject: [PATCH 17/30] glob kwargs and list error --- icepyx/core/read.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 90bc6be9d..9176e6cc4 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -277,6 +277,8 @@ class Read: The default describes files downloaded directly from NSIDC (subsetted and non-subsetted) for most products (e.g. ATL06). The ATL11 filename pattern from NSIDC is: 'ATL{product:2}_{rgt:4}{orbitsegment:2}_{cycles:4}_{version:3}_{revision:2}.h5'. **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. + glob_kwargs : dict, default {} + Additional arguments to be passed into the [glob.glob()](https://docs.python.org/3/library/glob.html#glob.glob)function out_obj_type : object, default xarray.Dataset The desired format for the data to be read in. @@ -313,13 +315,12 @@ class Read: # ---------------------------------------------------------------------- # Constructors - # TODO -- what if user passes an empty list, or the glob string returns empty - def __init__( self, data_source, product=None, filename_pattern=None, + glob_kwargs = {}, out_obj_type=None, # xr.Dataset, ): # Raise warnings for depreciated arguments @@ -351,9 +352,9 @@ def __init__( self._filelist = data_source elif os.path.isdir(data_source): data_source = os.path.join(data_source, '*') - self._filelist = glob.glob(data_source) + self._filelist = glob.glob(data_source, **glob_kwargs) else: - self._filelist = glob.glob(data_source) + self._filelist = glob.glob(data_source, **glob_kwargs) # Remove any directories from the list self._filelist = [f for f in self._filelist if not os.path.isdir(f)] @@ -387,6 +388,11 @@ def __init__( 'Please provide a valid `data_source` parameter indicating files of a single ' 'product' ) + elif len(all_products) == 0: + raise TypeError( + 'No files found matching the specified `data_source`. Check your glob ' + 'string or file list.' + ) else: # Assign the identified product to the property self._product = all_products[0] From 203f3adafc085bce44d0fd993b5932f60366f33c Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Fri, 8 Sep 2023 14:44:22 +0000 Subject: [PATCH 18/30] formatting updates --- .../example_notebooks/IS2_data_read-in.ipynb | 42 ++++++++++--------- icepyx/core/read.py | 18 ++++---- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index 9288e7da3..0ab4a4dfa 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -262,7 +262,9 @@ "user_expressions": [] }, "source": [ - "If specifying a directory, glob will not by default search all of the subdirectories for matching filepaths. If this is the search method you would like, you can achieve this by either:\n", + "glob will not by default search all of the subdirectories for matching filepaths, but it has the ability to do so. To search recursively you need to 1) use `/**/` in the filepath to match any level of nested folders and 2) use the `recursive=True` argument. \n", + "\n", + "If you would like to search recursively, you can achieve this by either:\n", "1. passing the `recursive` argument into `glob_kwargs`\n", "2. using glob directly to create a list of filepaths" ] @@ -280,24 +282,11 @@ { "cell_type": "code", "execution_count": null, - "id": "be79b0dd-efcf-4d50-bdb0-8e3ae8e8e38c", + "id": "e276b876-9ec7-4991-8520-05c97824b896", "metadata": {}, "outputs": [], "source": [ - "import glob" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5d088571-496d-479a-9fb7-833ed7e98676", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "list_of_files = glob.glob('/path/to/my/folder', recursive=True)\n", - "ipx.Read(list_of_files)" + "ipx.Read('/path/to/**/folder', glob_kwargs={'recursive': True})" ] }, { @@ -313,11 +302,24 @@ { "cell_type": "code", "execution_count": null, - "id": "e276b876-9ec7-4991-8520-05c97824b896", + "id": "be79b0dd-efcf-4d50-bdb0-8e3ae8e8e38c", "metadata": {}, "outputs": [], "source": [ - "ipx.Read('/path/to/my/folder', glob_kwargs={'recursive': True})" + "import glob" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d088571-496d-479a-9fb7-833ed7e98676", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "list_of_files = glob.glob('/path/to/**/folder', recursive=True)\n", + "ipx.Read(list_of_files)" ] }, { @@ -328,9 +330,9 @@ }, "source": [ "```{admonition} Read Module Update\n", - "Previously, icepyx required two additional things: 1) that you specify a `product` and 2) that your files either matched the default `filename_pattern` or that the user provided their own `filename_pattern`. These two requirements have been removed. `product` is not read directly from the file metadata (the root group's `short_name` attribute). Flexibility to specify multiple files via the `filename_pattern` has been replaced with [glob string](https://docs.python.org/3/library/glob.html) and allowing a list of filepaths as an argument.\n", + "Previously, icepyx required two additional conditions: 1) a `product` argument and 2) that your files either matched the default `filename_pattern` or that the user provided their own `filename_pattern`. These two requirements have been removed. `product` is now read directly from the file metadata (the root group's `short_name` attribute). Flexibility to specify multiple files via the `filename_pattern` has been replaced with the [glob string](https://docs.python.org/3/library/glob.html) feature, and by allowing a list of filepaths as an argument.\n", "\n", - "These arguments have been maintained for backward compatibility, but will be fully removed in icepyx version 1.0.0.\n", + "The `product` and `filename_pattern` arguments have been maintained for backwards compatibility, but will be fully removed in icepyx version 1.0.0.\n", "```" ] }, diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 9176e6cc4..f5cb53f8f 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -327,7 +327,8 @@ def __init__( if filename_pattern: warnings.warn( 'The `filename_pattern` argument is depreciated. Instead please provide a ' - 'string, list, or glob string to the `data_source` argument.' + 'string, list, or glob string to the `data_source` argument.', + stacklevel=2, ) if product: @@ -337,7 +338,8 @@ def __init__( 'contains files with multiple products the `product` argument will be used ' 'to filter that list. In all other cases the product argument is ignored. ' 'The recommended approach is to not include a `product` argument and instead ' - 'provide a `data_source` with files of only a single product type`.' + 'provide a `data_source` with files of only a single product type`.', + stacklevel=2, ) # Create the filelist from the `data_source` argument @@ -369,7 +371,8 @@ def __init__( if product: warnings.warn( f'Multiple products found in list of files: {product_dict}. Files that ' - 'do not match the user specified product will be removed from processing.' + 'do not match the user specified product will be removed from processing.', + stacklevel=2, ) self._filelist = [] for key, value in product_dict.items(): @@ -400,7 +403,8 @@ def __init__( if product and self._product != product: warnings.warn( f'User specified product {product} does not match the product from the file' - ' metadata {self._product}' + ' metadata {self._product}', + stacklevel=2, ) if out_obj_type is not None: @@ -442,21 +446,21 @@ def vars(self): @property def filelist(self): """ - A read-only property for viewing the list of files represented by this Read object. + Return the list of files represented by this Read object. """ return self._filelist @property def num_files(self): """ - Return the number of files that are being processed + Return the number of files that are being processed. """ return len(self.filelist) @property def product(self): """ - A read-only property for the user to view the product associated with the Read object. + Return the product associated with the Read object. """ return self._product From 10d15910a1f82ec2b18ba61eff647e243d44651c Mon Sep 17 00:00:00 2001 From: Rachel Wegener <35503632+rwegener2@users.noreply.github.com> Date: Tue, 12 Sep 2023 09:18:22 -0400 Subject: [PATCH 19/30] Apply suggestions from code review Co-authored-by: Jessica Scheick --- icepyx/core/read.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index f5cb53f8f..c45a72fa9 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -272,8 +272,8 @@ class Read: Available data products can be found at: https://nsidc.org/data/icesat-2/data-sets **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. The dataset product is read from the file metadata. - filename_pattern : string, default 'ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5' - String that shows the filename pattern as required for Intake's path_as_pattern argument. + filename_pattern : string, default None + String that shows the filename pattern as previously required for Intake's path_as_pattern argument. The default describes files downloaded directly from NSIDC (subsetted and non-subsetted) for most products (e.g. ATL06). The ATL11 filename pattern from NSIDC is: 'ATL{product:2}_{rgt:4}{orbitsegment:2}_{cycles:4}_{version:3}_{revision:2}.h5'. **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. @@ -292,23 +292,18 @@ class Read: Examples -------- Reading a single file - ``` - ipx.Read('/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5') # doctest: +SKIP - ``` + >>> ipx.Read('/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5') # doctest: +SKIP + Reading all files in a directory - ``` - ipx.Read('/path/to/data/') # doctest: +SKIP - ``` + >>> ipx.Read('/path/to/data/') # doctest: +SKIP + Reading files that match a particular pattern (here, all .h5 files that start with `processed_ATL06_`). - ``` - ipx.Read('/path/to/data/processed_ATL06_*.h5') # doctest: +SKIP - ``` + >>> ipx.Read('/path/to/data/processed_ATL06_*.h5') # doctest: +SKIP + Reading a specific list of files - ``` - list_of_files = ['/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', + >>> list_of_files = ['/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5'] - ipx.Read(list_of_files) # doctest: +SKIP - ``` + >>> ipx.Read(list_of_files) # doctest: +SKIP """ @@ -326,7 +321,7 @@ def __init__( # Raise warnings for depreciated arguments if filename_pattern: warnings.warn( - 'The `filename_pattern` argument is depreciated. Instead please provide a ' + 'The `filename_pattern` argument is deprecated. Instead please provide a ' 'string, list, or glob string to the `data_source` argument.', stacklevel=2, ) From 0b23d1e12808fb69afa85d1fa5168c17221f52f2 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 12 Sep 2023 13:24:45 +0000 Subject: [PATCH 20/30] remove num_files --- doc/source/user_guide/documentation/read.rst | 1 - icepyx/core/read.py | 7 ------- 2 files changed, 8 deletions(-) diff --git a/doc/source/user_guide/documentation/read.rst b/doc/source/user_guide/documentation/read.rst index 892f98087..68da03b1d 100644 --- a/doc/source/user_guide/documentation/read.rst +++ b/doc/source/user_guide/documentation/read.rst @@ -20,7 +20,6 @@ Attributes :toctree: ../../_icepyx/ Read.filelist - Read.num_files Read.product Read.vars diff --git a/icepyx/core/read.py b/icepyx/core/read.py index c45a72fa9..b139ca567 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -444,13 +444,6 @@ def filelist(self): Return the list of files represented by this Read object. """ return self._filelist - - @property - def num_files(self): - """ - Return the number of files that are being processed. - """ - return len(self.filelist) @property def product(self): From 6f5beadcb8bca332fbf9fbda79310e075bbd8af3 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 12 Sep 2023 13:28:03 +0000 Subject: [PATCH 21/30] fix docs test typo --- icepyx/core/read.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index b139ca567..4300cebbc 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -301,8 +301,10 @@ class Read: >>> ipx.Read('/path/to/data/processed_ATL06_*.h5') # doctest: +SKIP Reading a specific list of files - >>> list_of_files = ['/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', - '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5'] + >>> list_of_files = [ + '/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', + '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5', + ] >>> ipx.Read(list_of_files) # doctest: +SKIP """ From 035ee5ab1e33dc43a471c36286a59c036d0cb292 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 12 Sep 2023 13:37:15 +0000 Subject: [PATCH 22/30] trying again to fix the build --- icepyx/core/read.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 4300cebbc..b9a6e672e 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -302,9 +302,9 @@ class Read: Reading a specific list of files >>> list_of_files = [ - '/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', - '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5', - ] + ... '/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', + ... '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5', + ... ] >>> ipx.Read(list_of_files) # doctest: +SKIP """ From 903c351007bc7245bf4d107b48b1f38c67acf900 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 12 Sep 2023 13:48:27 +0000 Subject: [PATCH 23/30] add feedback to docs page --- .../example_notebooks/IS2_data_read-in.ipynb | 42 +++++++------------ 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index 0ab4a4dfa..4cdd3bf5a 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -177,11 +177,7 @@ "* a string path to directory - all files from the directory will be opened\n", "* a string path to single file - one file will be opened\n", "* a list of filepaths - all files in the list will be opened\n", - "* a glob string (see [glob](https://docs.python.org/3/library/glob.html)) - any files matching the glob pattern will be opened\n", - "\n", - "S3 bucket data access is currently under development, and requires you are registered with NSIDC as a beta tester for cloud-based ICESat-2 data.\n", - "icepyx is working to ensure a smooth transition to working with remote files.\n", - "We'd love your help exploring and testing these features as they become available!" + "* a glob string (see [glob](https://docs.python.org/3/library/glob.html)) - any files matching the glob pattern will be opened" ] }, { @@ -215,16 +211,6 @@ "# '/my/other/data/ATL06/processed_ATL06_20191202102922_10160505_006_01.h5']" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "e683ebf7", - "metadata": {}, - "outputs": [], - "source": [ - "# urlpath = 's3://nsidc-cumulus-prod-protected/ATLAS/ATL03/004/2019/11/30/ATL03_20191130221008_09930503_004_01.h5'" - ] - }, { "cell_type": "markdown", "id": "ba3ebeb0-3091-4712-b0f7-559ddb95ca5a", @@ -238,9 +224,9 @@ "\n", "glob works using `*` and `?` as wildcard characters, where `*` matches any number of characters and `?` matches a single character. For example:\n", "\n", - "* `/this/path/*.h5`: refers to all files `.h5` files in the `/this/path` folder\n", - "* `ATL??.h5`: refers to any `.h5` file that starts with `ATL` and then has any 2 characters after it\n", - "* `/this/path/ATL??/*.h5`: refers to all `.h5` files that are in a subfolder of `/this/path` which has a filename of `ATL` followed by any 2 characters\n", + "* `/this/path/*.h5`: refers to all `.h5` files in the `/this/path` folder (Example matches: \"/this/path/processed_ATL03_20191130221008_09930503_006_01.h5\" or \"/this/path/myfavoriteicsat-2file.h5\")\n", + "* `/this/path/*ATL07*.h5`: refers to all `.h5` files in the `/this/path` folder that have ATL07 in the filename. (Example matches: \"/this/path/ATL07-02_20221012220720_03391701_005_01.h5\" or \"/this/path/processed_ATL07.h5\")\n", + "* `/this/path/ATL??/*.h5`: refers to all `.h5` files that are in a subfolder of `/this/path` and a subdirectory of `ATL` followed by any 2 characters (Example matches: \"/this/path/ATL03/processed_ATL03_20191130221008_09930503_006_01.h5\", \"/this/path/ATL06/myfile.h5\")\n", "\n", "See the glob documentation or other online explainer tutorials for more in depth explanation, or advanced glob paths such as character classes and ranges." ] @@ -289,6 +275,16 @@ "ipx.Read('/path/to/**/folder', glob_kwargs={'recursive': True})" ] }, + { + "cell_type": "markdown", + "id": "f5a1e85e-fc4a-405f-9710-0cb61b827f2c", + "metadata": { + "user_expressions": [] + }, + "source": [ + "You can use `glob_kwargs` for any additional argument to Python's builtin `glob.glob` that you would like to pass in via icepyx." + ] + }, { "cell_type": "markdown", "id": "76de9539-710c-49f6-9e9e-238849382c33", @@ -380,16 +376,6 @@ "reader.filelist" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "248590ba-b468-4ca5-999f-4323b704008e", - "metadata": {}, - "outputs": [], - "source": [ - "reader.num_files" - ] - }, { "cell_type": "code", "execution_count": null, From 5e06de94da0c492b4b3cc94a5b4d834b0dc829a4 Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Thu, 14 Sep 2023 13:32:52 +0000 Subject: [PATCH 24/30] fix typo --- icepyx/core/read.py | 1 - 1 file changed, 1 deletion(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index baeba27f4..966df8d08 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -338,7 +338,6 @@ def __init__( if data_source is None: raise ValueError("data_source is a required arguemnt") - ) # Raise warnings for deprecated arguments if filename_pattern: From b2c273518bee22f8f1417d51cdaf3a39958bc56e Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Mon, 9 Oct 2023 15:59:03 -0400 Subject: [PATCH 25/30] depreciate -> deprecate --- icepyx/core/read.py | 80 ++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index 966df8d08..e687511d1 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -272,18 +272,18 @@ class Read: product : string ICESat-2 data product ID, also known as "short name" (e.g. ATL03). Available data products can be found at: https://nsidc.org/data/icesat-2/data-sets - **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. The dataset product is read from the file metadata. + **Deprecation warning:** This argument is no longer required and will be deprecated in version 1.0.0. The dataset product is read from the file metadata. filename_pattern : string, default None String that shows the filename pattern as previously required for Intake's path_as_pattern argument. The default describes files downloaded directly from NSIDC (subsetted and non-subsetted) for most products (e.g. ATL06). The ATL11 filename pattern from NSIDC is: 'ATL{product:2}_{rgt:4}{orbitsegment:2}_{cycles:4}_{version:3}_{revision:2}.h5'. - **Depreciation warning:** This argument is no longer required and will be depreciated in version 1.0.0. - + **Deprecation warning:** This argument is no longer required and will be deprecated in version 1.0.0. + catalog : string, default None Full path to an Intake catalog for reading in data. If you still need to create a catalog, leave as default. - **Deprecation warning:** This argument has been depreciated. Please use the data_source argument to pass in valid data. + **Deprecation warning:** This argument has been deprecated. Please use the data_source argument to pass in valid data. glob_kwargs : dict, default {} Additional arguments to be passed into the [glob.glob()](https://docs.python.org/3/library/glob.html#glob.glob)function @@ -310,7 +310,7 @@ class Read: Reading a specific list of files >>> list_of_files = [ - ... '/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', + ... '/path/to/data/processed_ATL06_20190226005526_09100205_006_02.h5', ... '/path/to/more/data/processed_ATL06_20191202102922_10160505_006_01.h5', ... ] >>> ipx.Read(list_of_files) # doctest: +SKIP @@ -319,42 +319,42 @@ class Read: # ---------------------------------------------------------------------- # Constructors - + def __init__( self, data_source=None, # DevNote: Make this a required arg when catalog is removed product=None, filename_pattern=None, catalog=None, - glob_kwargs = {}, + glob_kwargs={}, out_obj_type=None, # xr.Dataset, ): # Raise error for deprecated argument if catalog: raise DeprecationError( - 'The `catalog` argument has been deprecated and intake is no longer supported. ' - 'Please use the `data_source` argument to specify your dataset instead.' + "The `catalog` argument has been deprecated and intake is no longer supported. " + "Please use the `data_source` argument to specify your dataset instead." ) - + if data_source is None: raise ValueError("data_source is a required arguemnt") - + # Raise warnings for deprecated arguments if filename_pattern: warnings.warn( - 'The `filename_pattern` argument is deprecated. Instead please provide a ' - 'string, list, or glob string to the `data_source` argument.', + "The `filename_pattern` argument is deprecated. Instead please provide a " + "string, list, or glob string to the `data_source` argument.", stacklevel=2, ) - + if product: product = is2ref._validate_product(product) warnings.warn( - 'The `product` argument is no longer required. If the `data_source` argument given ' - 'contains files with multiple products the `product` argument will be used ' - 'to filter that list. In all other cases the product argument is ignored. ' - 'The recommended approach is to not include a `product` argument and instead ' - 'provide a `data_source` with files of only a single product type`.', + "The `product` argument is no longer required. If the `data_source` argument given " + "contains files with multiple products the `product` argument will be used " + "to filter that list. In all other cases the product argument is ignored. " + "The recommended approach is to not include a `product` argument and instead " + "provide a `data_source` with files of only a single product type`.", stacklevel=2, ) @@ -369,7 +369,7 @@ def __init__( elif isinstance(data_source, list): self._filelist = data_source elif os.path.isdir(data_source): - data_source = os.path.join(data_source, '*') + data_source = os.path.join(data_source, "*") self._filelist = glob.glob(data_source, **glob_kwargs) else: self._filelist = glob.glob(data_source, **glob_kwargs) @@ -380,14 +380,14 @@ def __init__( product_dict = {} for file_ in self._filelist: product_dict[file_] = self._extract_product(file_) - + # Raise warnings or errors for muliple products or products not matching the user-specified product all_products = list(set(product_dict.values())) if len(all_products) > 1: if product: warnings.warn( - f'Multiple products found in list of files: {product_dict}. Files that ' - 'do not match the user specified product will be removed from processing.', + f"Multiple products found in list of files: {product_dict}. Files that " + "do not match the user specified product will be removed from processing.", stacklevel=2, ) self._filelist = [] @@ -396,21 +396,21 @@ def __init__( self._filelist.append(key) if len(self._filelist) == 0: raise TypeError( - 'No files found in the file list matching the user-specified ' - 'product type' + "No files found in the file list matching the user-specified " + "product type" ) # Use the cleaned filelist to assign a product self._product = product else: raise TypeError( - f'Multiple product types were found in the file list: {product_dict}.' - 'Please provide a valid `data_source` parameter indicating files of a single ' - 'product' + f"Multiple product types were found in the file list: {product_dict}." + "Please provide a valid `data_source` parameter indicating files of a single " + "product" ) elif len(all_products) == 0: raise TypeError( - 'No files found matching the specified `data_source`. Check your glob ' - 'string or file list.' + "No files found matching the specified `data_source`. Check your glob " + "string or file list." ) else: # Assign the identified product to the property @@ -418,11 +418,11 @@ def __init__( # Raise a warning if the metadata-located product differs from the user-specified product if product and self._product != product: warnings.warn( - f'User specified product {product} does not match the product from the file' - ' metadata {self._product}', + f"User specified product {product} does not match the product from the file" + " metadata {self._product}", stacklevel=2, ) - + if out_obj_type is not None: print( "Output object type will be an xarray DataSet - " @@ -458,7 +458,7 @@ def vars(self): ) return self._read_vars - + @property def filelist(self): """ @@ -475,21 +475,21 @@ def product(self): # ---------------------------------------------------------------------- # Methods - + @staticmethod def _extract_product(filepath): """ Read the product type from the metadata of the file. Return the product as a string. """ - with h5py.File(filepath, 'r') as f: - try: - product = f.attrs['short_name'].decode() + with h5py.File(filepath, "r") as f: + try: + product = f.attrs["short_name"].decode() product = is2ref._validate_product(product) # TODO test that this is the proper error except KeyError: - raise 'Unable to parse the product name from file metadata' + raise "Unable to parse the product name from file metadata" return product - + @staticmethod def _check_source_for_pattern(source, filename_pattern): """ From 6b953f9c63151c20a5224dc9e38db5b73dae02f8 Mon Sep 17 00:00:00 2001 From: Rachel Wegener <35503632+rwegener2@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:13:51 -0400 Subject: [PATCH 26/30] Apply suggestions from code review Co-authored-by: Jessica Scheick --- icepyx/core/read.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index e687511d1..c63c6d954 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -268,6 +268,7 @@ class Read: ---------- data_source : string, List A string or list which specifies the files to be read. The string can be either: 1) the path of a single file 2) the path to a directory or 3) a [glob string](https://docs.python.org/3/library/glob.html). + The List must be a list of strings, each of which is the path of a single file. product : string ICESat-2 data product ID, also known as "short name" (e.g. ATL03). @@ -322,7 +323,7 @@ class Read: def __init__( self, - data_source=None, # DevNote: Make this a required arg when catalog is removed + data_source=None, product=None, filename_pattern=None, catalog=None, @@ -381,7 +382,7 @@ def __init__( for file_ in self._filelist: product_dict[file_] = self._extract_product(file_) - # Raise warnings or errors for muliple products or products not matching the user-specified product + # Raise warnings or errors for multiple products or products not matching the user-specified product all_products = list(set(product_dict.values())) if len(all_products) > 1: if product: From 45704a4e94368b7fe64466908aaff45fdc78f5db Mon Sep 17 00:00:00 2001 From: Rachel Wegener <35503632+rwegener2@users.noreply.github.com> Date: Tue, 10 Oct 2023 11:33:16 -0400 Subject: [PATCH 27/30] elaborate on multiple products warning --- icepyx/core/read.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index c63c6d954..eb4d1168d 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -388,7 +388,9 @@ def __init__( if product: warnings.warn( f"Multiple products found in list of files: {product_dict}. Files that " - "do not match the user specified product will be removed from processing.", + "do not match the user specified product will be removed from processing.\n" + "Filtering files using a `product` argument is deprecated. Please use the " + "`data_source` argument to specify a list of files with the same product.", stacklevel=2, ) self._filelist = [] From 2bf28086f00bab031390bf85cc81baa5257e8bce Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 10 Oct 2023 15:46:56 +0000 Subject: [PATCH 28/30] clarify glob section --- doc/source/example_notebooks/IS2_data_read-in.ipynb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/source/example_notebooks/IS2_data_read-in.ipynb b/doc/source/example_notebooks/IS2_data_read-in.ipynb index 4cdd3bf5a..9bbac368b 100644 --- a/doc/source/example_notebooks/IS2_data_read-in.ipynb +++ b/doc/source/example_notebooks/IS2_data_read-in.ipynb @@ -248,11 +248,13 @@ "user_expressions": [] }, "source": [ - "glob will not by default search all of the subdirectories for matching filepaths, but it has the ability to do so. To search recursively you need to 1) use `/**/` in the filepath to match any level of nested folders and 2) use the `recursive=True` argument. \n", + "glob will not by default search all of the subdirectories for matching filepaths, but it has the ability to do so.\n", "\n", "If you would like to search recursively, you can achieve this by either:\n", - "1. passing the `recursive` argument into `glob_kwargs`\n", - "2. using glob directly to create a list of filepaths" + "1. passing the `recursive` argument into `glob_kwargs` and including `\\**\\` in your filepath\n", + "2. using glob directly to create a list of filepaths\n", + "\n", + "Each of these two methods are shown below." ] }, { From 12428817b9445daba3933e5a75d885d622aef1ad Mon Sep 17 00:00:00 2001 From: Rachel Wegener Date: Tue, 10 Oct 2023 16:05:26 +0000 Subject: [PATCH 29/30] test product name error --- icepyx/core/read.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/icepyx/core/read.py b/icepyx/core/read.py index eb4d1168d..a85ee659b 100644 --- a/icepyx/core/read.py +++ b/icepyx/core/read.py @@ -488,9 +488,10 @@ def _extract_product(filepath): try: product = f.attrs["short_name"].decode() product = is2ref._validate_product(product) - # TODO test that this is the proper error except KeyError: - raise "Unable to parse the product name from file metadata" + raise AttributeError( + f"Unable to extract the product name from file metadata." + ) return product @staticmethod From e18cf7a67adf9944de9a054d6ee0fcb91211c881 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Wed, 18 Oct 2023 17:49:35 +0000 Subject: [PATCH 30/30] GitHub action UML generation auto-update --- .../documentation/classes_dev_uml.svg | 122 +++++++++--------- .../documentation/classes_user_uml.svg | 21 +-- 2 files changed, 72 insertions(+), 71 deletions(-) diff --git a/doc/source/user_guide/documentation/classes_dev_uml.svg b/doc/source/user_guide/documentation/classes_dev_uml.svg index 34e13b41c..0cd08c9e9 100644 --- a/doc/source/user_guide/documentation/classes_dev_uml.svg +++ b/doc/source/user_guide/documentation/classes_dev_uml.svg @@ -4,11 +4,11 @@ - + classes_dev_uml - + icepyx.core.auth.AuthenticationError @@ -139,38 +139,38 @@ icepyx.core.icesat2data.Icesat2Data - -Icesat2Data - - -__init__() + +Icesat2Data + + +__init__() icepyx.core.exceptions.NsidcQueryError - -NsidcQueryError - -errmsg -msgtxt : str - -__init__(errmsg, msgtxt) -__str__() + +NsidcQueryError + +errmsg +msgtxt : str + +__init__(errmsg, msgtxt) +__str__() icepyx.core.exceptions.QueryError - -QueryError - - - + +QueryError + + + icepyx.core.exceptions.NsidcQueryError->icepyx.core.exceptions.QueryError - - + + @@ -235,24 +235,24 @@ icepyx.core.read.Read - -Read - -_filelist : NoneType, list -_out_obj : Dataset -_pattern : str -_prod : str -_read_vars -_source_type : str -data_source -vars - -__init__(data_source, product, filename_pattern, catalog, out_obj_type) -_add_vars_to_ds(is2ds, ds, grp_path, wanted_groups_tiered, wanted_dict) -_build_dataset_template(file) -_build_single_file_dataset(file, groups_list) -_check_source_for_pattern(source, filename_pattern) -_combine_nested_vars(is2ds, ds, grp_path, wanted_dict) + +Read + +_filelist : NoneType, list +_out_obj : Dataset +_product : NoneType, str +_read_vars +filelist +product +vars + +__init__(data_source, product, filename_pattern, catalog, glob_kwargs, out_obj_type) +_add_vars_to_ds(is2ds, ds, grp_path, wanted_groups_tiered, wanted_dict) +_build_dataset_template(file) +_build_single_file_dataset(file, groups_list) +_check_source_for_pattern(source, filename_pattern) +_combine_nested_vars(is2ds, ds, grp_path, wanted_dict) +_extract_product(filepath) _read_single_grp(file, grp_path) load() @@ -366,30 +366,30 @@ icepyx.core.variables.Variables->icepyx.core.read.Read - - -_read_vars + + +_read_vars icepyx.core.visualization.Visualize - -Visualize - -bbox : list -cycles : NoneType -date_range : NoneType -product : NoneType, str -tracks : NoneType - -__init__(query_obj, product, spatial_extent, date_range, cycles, tracks) -generate_OA_parameters(): list -grid_bbox(binsize): list -make_request(base_url, payload) -parallel_request_OA(): da.array -query_icesat2_filelist(): tuple -request_OA_data(paras): da.array -viz_elevation(): (hv.DynamicMap, hv.Layout) + +Visualize + +bbox : list +cycles : NoneType +date_range : NoneType +product : NoneType, str +tracks : NoneType + +__init__(query_obj, product, spatial_extent, date_range, cycles, tracks) +generate_OA_parameters(): list +grid_bbox(binsize): list +make_request(base_url, payload) +parallel_request_OA(): da.array +query_icesat2_filelist(): tuple +request_OA_data(paras): da.array +viz_elevation(): (hv.DynamicMap, hv.Layout) diff --git a/doc/source/user_guide/documentation/classes_user_uml.svg b/doc/source/user_guide/documentation/classes_user_uml.svg index 640f76815..a9c116469 100644 --- a/doc/source/user_guide/documentation/classes_user_uml.svg +++ b/doc/source/user_guide/documentation/classes_user_uml.svg @@ -201,13 +201,14 @@ icepyx.core.read.Read - -Read - -data_source -vars - -load() + +Read + +filelist +product +vars + +load() @@ -300,9 +301,9 @@ icepyx.core.variables.Variables->icepyx.core.read.Read - - -_read_vars + + +_read_vars