diff --git a/.gitignore b/.gitignore index 24f75cb..f8fec0a 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ _*.c *.shp *.shx *.tif +*.vrt *.zarr # Logs and databases # ###################### diff --git a/IS2view/api.py b/IS2view/api.py index 5cd1ec3..ce17e77 100644 --- a/IS2view/api.py +++ b/IS2view/api.py @@ -1,7 +1,7 @@ #!/usr/bin/env python u""" api.py -Written by Tyler Sutterley (04/2024) +Written by Tyler Sutterley (06/2024) Plotting tools for visualizing rioxarray variables on leaflet maps PYTHON DEPENDENCIES: @@ -28,6 +28,7 @@ https://xyzservices.readthedocs.io/en/stable/ UPDATE HISTORY: + Updated 06/2024: use wrapper to importlib for optional dependencies Updated 04/2024: add connections and functions for changing variables and other attributes of the leaflet map visualization simplify and generalize mapping between observables and functionals @@ -56,20 +57,21 @@ import collections.abc from traitlets import HasTraits, Float, Tuple, observe from traitlets.utils.bunch import Bunch +from IS2view.utilities import import_dependency # attempt imports -try: - import geopandas as gpd -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("geopandas not available") -try: - import ipywidgets -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("ipywidgets not available") -try: - import ipyleaflet -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("ipyleaflet not available") +gpd = import_dependency('geopandas') +ipywidgets = import_dependency('ipywidgets') +ipyleaflet = import_dependency('ipyleaflet') +owslib = import_dependency('owslib') +owslib.wms = import_dependency('owslib.wms') +rio = import_dependency('rasterio') +rio.transform = import_dependency('rasterio.transform') +rio.warp = import_dependency('rasterio.warp') +xr = import_dependency('xarray') +xyzservices = import_dependency('xyzservices') + +# attempt matplotlib imports try: import matplotlib import matplotlib.cm as cm @@ -81,23 +83,6 @@ matplotlib.rcParams['mathtext.default'] = 'regular' except (AttributeError, ImportError, ModuleNotFoundError) as exc: logging.critical("matplotlib not available") -try: - import owslib.wms -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("owslib not available") -try: - import rasterio.transform - import rasterio.warp -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("rasterio not available") -try: - import xarray as xr -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("xarray not available") -try: - import xyzservices -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("xyzservices not available") # set environmental variable for anonymous s3 access os.environ['AWS_NO_SIGN_REQUEST'] = 'YES' @@ -230,6 +215,8 @@ def _tile_provider(provider): # create traitlets of basemap providers basemaps = _load_dict(providers) +# set default map dimensions +_default_layout = ipywidgets.Layout(width='70%', height='600px') # draw ipyleaflet map class Leaflet: @@ -241,6 +228,8 @@ class Leaflet: ``ipyleaflet.Map`` basemap : obj or NoneType Basemap for the ``ipyleaflet.Map`` + layout : obj, default ``ipywidgets.Layout(width='70%', height='600px')`` + Layout for the ``ipyleaflet.Map`` attribution : bool, default False Include layer attributes on leaflet map scale_control : bool, default False @@ -280,6 +269,7 @@ class Leaflet: def __init__(self, projection, **kwargs): # set default keyword arguments kwargs.setdefault('map', None) + kwargs.setdefault('layout', _default_layout) kwargs.setdefault('attribution', False) kwargs.setdefault('full_screen_control', False) kwargs.setdefault('scale_control', False) @@ -300,7 +290,9 @@ def __init__(self, projection, **kwargs): zoom=kwargs['zoom'], max_zoom=5, attribution_control=kwargs['attribution'], basemap=kwargs['basemap'], - crs=projections['EPSG:3413']) + crs=projections['EPSG:3413'], + layout=kwargs['layout'] + ) self.crs = 'EPSG:3413' elif (projection == 'South'): kwargs.setdefault('basemap', @@ -310,7 +302,9 @@ def __init__(self, projection, **kwargs): zoom=kwargs['zoom'], max_zoom=5, attribution_control=kwargs['attribution'], basemap=kwargs['basemap'], - crs=projections['EPSG:3031']) + crs=projections['EPSG:3031'], + layout=kwargs['layout'] + ) self.crs = 'EPSG:3031' else: # use a predefined ipyleaflet map @@ -508,7 +502,7 @@ def plot_basemap(self, ax=None, **kwargs): ax: obj, default None Figure axis kwargs: dict, default {} - Additional keyword arguments for ``wms.getmap`` + Additional keyword arguments for ``owslib.wms.getmap`` """ # set default keyword arguments kwargs.setdefault('layers', ['BlueMarble_NextGeneration']) @@ -777,12 +771,8 @@ def plot(self, m, **kwargs): # reduce to variable and lag self._variable = copy.copy(kwargs['variable']) self.lag = int(kwargs['lag']) - if (self._ds[self._variable].ndim == 3) and ('time' in self._ds[self._variable].dims): - self._ds_selected = self._ds[self._variable].sel(time=self._ds.time[self.lag]) - elif (self._ds[self._variable].ndim == 3) and ('band' in self._ds[self._variable].dims): - self._ds_selected = self._ds[self._variable].sel(band=1) - else: - self._ds_selected = self._ds[self._variable] + # select data variable + self.set_dataset() # get the normalization bounds self.get_norm_bounds(**kwargs) # create matplotlib normalization @@ -911,7 +901,7 @@ def get_bounds(self): """get the bounds of the leaflet map in geographical coordinates """ self.get_bbox() - lon, lat = rasterio.warp.transform( + lon, lat = rio.warp.transform( self.crs['name'], 'EPSG:4326', [self.sw['x'], self.ne['x']], [self.sw['y'], self.ne['y']]) @@ -1000,7 +990,7 @@ def clip_image(self, ds): # attempt to get the coordinate reference system of the dataset self.get_crs() # convert map bounds to coordinate reference system of image - minx, miny, maxx, maxy = rasterio.warp.transform_bounds( + minx, miny, maxx, maxy = rio.warp.transform_bounds( self.crs['name'], self._ds.rio.crs, self.sw['x'], self.sw['y'], self.ne['x'], self.ne['y']) @@ -1023,14 +1013,14 @@ def clip_image(self, ds): # warp image to map bounds and resolution # input and output affine transformations src_transform = ds.rio.transform() - dst_transform = rasterio.transform.from_origin(minx, maxy, + dst_transform = rio.transform.from_origin(minx, maxy, self.resolution, self.resolution) # allocate for output warped image dst_width = int((maxx - minx)//self.resolution) dst_height = int((maxy - miny)//self.resolution) dst_data = np.zeros((dst_height, dst_width), dtype=ds.dtype.type) # warp image to output resolution - rasterio.warp.reproject(source=ds.values, destination=dst_data, + rio.warp.reproject(source=ds.values, destination=dst_data, src_transform=src_transform, src_crs=self._ds.rio.crs, src_nodata=np.nan, @@ -1148,14 +1138,10 @@ def set_observables(self, widget, **kwargs): except (AttributeError, NameError, ValueError) as exc: pass - def set_variable(self, sender): - """update the dataframe variable for a new selected variable + def set_dataset(self): + """Select the dataset for the selected variable + and time lag """ - # only update variable if a new final - if isinstance(sender['new'], str): - self._variable = sender['new'] - else: - return # reduce to variable and lag if (self._ds[self._variable].ndim == 3) and ('time' in self._ds[self._variable].dims): self._ds_selected = self._ds[self._variable].sel(time=self._ds.time[self.lag]) @@ -1163,6 +1149,17 @@ def set_variable(self, sender): self._ds_selected = self._ds[self._variable].sel(band=1) else: self._ds_selected = self._ds[self._variable] + + def set_variable(self, sender): + """update the plotted variable + """ + # only update variable if a new final + if isinstance(sender['new'], str): + self._variable = sender['new'] + else: + return + # reduce to variable and lag + self.set_dataset() # check if dynamic normalization is enabled if self._dynamic: self.get_norm_bounds() @@ -1263,7 +1260,7 @@ def handle_click(self, **kwargs): else: self._ds.rio.set_crs(crs) # get the clicked point in dataset coordinate reference system - x, y = rasterio.warp.transform('EPSG:4326', crs, [lon], [lat]) + x, y = rio.warp.transform('EPSG:4326', crs, [lon], [lat]) # find nearest point in dataset self._data = self._ds_selected.sel(x=x, y=y, method='nearest').values[0] self._units = self._ds[self._variable].attrs['units'] @@ -1575,7 +1572,7 @@ def point(self, ax, **kwargs): """ # convert point to dataset coordinate reference system lon, lat = self.geometry['coordinates'] - x, y = rasterio.warp.transform(self.crs, self._ds.rio.crs, [lon], [lat]) + x, y = rio.warp.transform(self.crs, self._ds.rio.crs, [lon], [lat]) # output time series for point self._data = np.zeros_like(self._ds.time) # reduce dataset to geometry @@ -1629,7 +1626,7 @@ def transect(self, ax, **kwargs): """ # convert linestring to dataset coordinate reference system lon, lat = np.transpose(self.geometry['coordinates']) - x, y = rasterio.warp.transform(self.crs, self._ds.rio.crs, lon, lat) + x, y = rio.warp.transform(self.crs, self._ds.rio.crs, lon, lat) # get coordinates of each grid cell gridx, gridy = np.meshgrid(self._ds.x, self._ds.y) # clip ice area to geometry @@ -1997,7 +1994,7 @@ def transect(self, ax, **kwargs): """ # convert linestring to dataset coordinate reference system lon, lat = np.transpose(self.geometry['coordinates']) - x, y = rasterio.warp.transform(self.crs, self._ds.rio.crs, lon, lat) + x, y = rio.warp.transform(self.crs, self._ds.rio.crs, lon, lat) # get coordinates of each grid cell gridx, gridy = np.meshgrid(self._ds.x, self._ds.y) # clip variable to geometry and create mask diff --git a/IS2view/convert.py b/IS2view/convert.py index 6cabea9..cb7f8d2 100644 --- a/IS2view/convert.py +++ b/IS2view/convert.py @@ -1,6 +1,6 @@ """ convert.py -Written by Tyler Sutterley (08/2023) +Written by Tyler Sutterley (06/2024) Utilities for converting gridded ICESat-2 files from native netCDF4 PYTHON DEPENDENCIES: @@ -13,6 +13,7 @@ https://docs.xarray.dev/en/stable/ UPDATE HISTORY: + Updated 06/2024: use wrapper to importlib for optional dependencies Updated 08/2023: use h5netcdf as the netCDF4 driver for xarray Updated 07/2023: use logging instead of warnings for import attempts Updated 06/2023: using pathlib to define and expand paths @@ -23,16 +24,11 @@ import logging import pathlib import numpy as np +from IS2view.utilities import import_dependency # attempt imports -try: - import h5netcdf -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("h5netcdf not available") -try: - import xarray as xr -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("xarray not available") +h5netcdf = import_dependency('h5netcdf') +xr = import_dependency('xarray') # default groups to skip _default_skip_groups = ('METADATA', 'orbit_info', 'quality_assessment',) diff --git a/IS2view/io.py b/IS2view/io.py index 00808c3..0159518 100644 --- a/IS2view/io.py +++ b/IS2view/io.py @@ -1,6 +1,6 @@ """ io.py -Written by Tyler Sutterley (10/2023) +Written by Tyler Sutterley (06/2024) Utilities for reading gridded ICESat-2 files using rasterio and xarray PYTHON DEPENDENCIES: @@ -18,6 +18,7 @@ https://docs.xarray.dev/en/stable/ UPDATE HISTORY: + Updated 06/2024: use wrapper to importlib for optional dependencies Updated 10/2023: use dask.delayed to read multiple files in parallel Updated 08/2023: use xarray h5netcdf to read files streaming from s3 add open_dataset function for opening multiple granules @@ -27,22 +28,13 @@ """ from __future__ import annotations import os -import logging +from IS2view.utilities import import_dependency # attempt imports -try: - import rioxarray - import rioxarray.merge -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("rioxarray not available") -try: - import dask -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("dask not available") -try: - import xarray as xr -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.critical("xarray not available") +rioxarray = import_dependency('rioxarray') +rioxarray.merge = import_dependency('rioxarray.merge') +dask = import_dependency('dask') +xr = import_dependency('xarray') # set environmental variable for anonymous s3 access os.environ['AWS_NO_SIGN_REQUEST'] = 'YES' diff --git a/IS2view/tools.py b/IS2view/tools.py index 8e2c89a..0379538 100644 --- a/IS2view/tools.py +++ b/IS2view/tools.py @@ -15,6 +15,7 @@ https://github.com/matplotlib/matplotlib UPDATE HISTORY: + Updated 06/2024: use wrapper to importlib for optional dependencies Updated 11/2023: set time steps using decimal years rather than lags setting dynamic colormap with float64 min and max Updated 08/2023: added options for ATL14/15 Release-03 data @@ -28,16 +29,11 @@ import copy import logging import numpy as np +from IS2view.utilities import import_dependency # attempt imports -try: - import ipywidgets -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("ipywidgets not available") -try: - import matplotlib.cm as cm -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("matplotlib not available") +ipywidgets = import_dependency('ipywidgets') +cm = import_dependency('matplotlib.cm') # set environmental variable for anonymous s3 access os.environ['AWS_NO_SIGN_REQUEST'] = 'YES' @@ -82,15 +78,16 @@ def __init__(self, **kwargs): self.directory.layout.display = 'none' # dropdown menu for setting ATL14/15 release - release_list = ['001', '002', '003'] + release_list = ['001', '002', '003', '004'] self.release = ipywidgets.Dropdown( options=release_list, - value='003', + value='004', description='Release:', description_tooltip=("Release: ATL14/15 data release\n\t" "001: Release-01\n\t" "002: Release-02\n\t" - "003: Release-03"), + "003: Release-03\n\t" + "004: Release-04"), disabled=False, style=self.style, ) @@ -166,7 +163,7 @@ def __init__(self, **kwargs): style=self.style, ) - # dropdown menu for selecting time lag to draw on map + # slider for selecting time lag to draw on map self.timelag = ipywidgets.IntSlider( description='Lag:', description_tooltip="Lag: time lag to draw on leaflet map", @@ -174,7 +171,7 @@ def __init__(self, **kwargs): style=self.style, ) - # dropdown menu for selecting time step to draw on map + # slider for selecting time step to draw on map self.timestep = ipywidgets.FloatSlider( description='Time:', description_tooltip="Time: time step to draw on leaflet map", @@ -182,6 +179,7 @@ def __init__(self, **kwargs): readout=True, readout_format='.2f', disabled=False, + continuous_update=False, style=self.style, ) @@ -381,7 +379,7 @@ def set_atl15_defaults(self, *args, **kwargs): # set default variable for group self.variable.value = variables[group] - def set_groups(self, sender): + def set_groups(self, *args): """sets the list of available groups for a release """ group_list = ['delta_h', 'dhdt_lag1', 'dhdt_lag4', 'dhdt_lag8'] @@ -423,11 +421,11 @@ def set_groups(self, sender): self.region.description_tooltip = description_tooltip def set_variables(self, *args): - """sets the list of available variables in a group + """sets the list of available variables """ - if any(args): + if isinstance(self.data_vars, list): # set list of available variables - self.variable.options = sorted(args[0].keys()) + self.variable.options = sorted(self.data_vars) else: # return to temporary defaults self.variable.options = ['delta_h', 'dhdt'] @@ -448,13 +446,32 @@ def set_dynamic(self, *args, **kwargs): self.range.value = [-5, 5] self.range.layout.display = 'inline-flex' - def set_time_steps(self, ds, epoch=2018.0): + def get_variables(self, d): + """ + Gets the available variables and time steps + + Parameters + ---------- + d : xarray.Dataset + xarray.Dataset object + """ + # data and time variables + self.data_vars = sorted(d.data_vars) + self.time_vars = d.time.values if 'time' in d else None + # set the default groups + self.set_groups() + # set the default variables + self.set_variables() + # set the default time steps + self.set_time_steps() + + def set_time_steps(self, *args, epoch=2018.0): """sets available time range """ # try setting the min and max time step try: # convert time to units - self.time = list(epoch + ds.time.values/365.25) + self.time = list(epoch + self.time_vars/365.25) self.timestep.max = self.time[-1] self.timestep.min = self.time[0] self.timestep.value = self.time[0] diff --git a/IS2view/utilities.py b/IS2view/utilities.py index 3f342d4..2bfd69f 100644 --- a/IS2view/utilities.py +++ b/IS2view/utilities.py @@ -1,10 +1,17 @@ #!/usr/bin/env python u""" utilities.py -Written by Tyler Sutterley (11/2023) +Written by Tyler Sutterley (05/2024) Download and management utilities +PYTHON DEPENDENCIES: + boto3: Amazon Web Services (AWS) SDK for Python + https://boto3.amazonaws.com/v1/documentation/api/latest/index.html + s3fs: FUSE-based file system backed by Amazon S3 + https://s3fs.readthedocs.io/en/latest/ + UPDATE HISTORY: + Updated 05/2024: add wrapper to importlib for optional dependencies Updated 11/2023: updated ssl context to fix deprecation error Updated 10/2023: filter CMR request type using regular expressions Updated 08/2023: added ATL14/15 Release-03 data products @@ -36,6 +43,7 @@ import pathlib import builtins import warnings +import importlib import posixpath import traceback import subprocess @@ -49,16 +57,6 @@ from urllib.parse import urlencode import urllib.request as urllib2 -# attempt imports -try: - import boto3 -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("boto3 not available") -try: - import s3fs -except (AttributeError, ImportError, ModuleNotFoundError) as exc: - logging.debug("s3fs not available") - # PURPOSE: get absolute path within a package from a relative path def get_data_path(relpath: list | str | pathlib.Path): """ @@ -78,6 +76,47 @@ def get_data_path(relpath: list | str | pathlib.Path): elif isinstance(relpath, (str, pathlib.Path)): return filepath.joinpath(relpath) +def import_dependency( + name: str, + extra: str = "", + raise_exception: bool = False + ): + """ + Import an optional dependency + + Adapted from ``pandas.compat._optional::import_optional_dependency`` + + Parameters + ---------- + name: str + Module name + extra: str, default "" + Additional text to include in the ``ImportError`` message + raise_exception: bool, default False + Raise an ``ImportError`` if the module is not found + + Returns + ------- + module: obj + Imported module + """ + # check if the module name is a string + msg = f"Invalid module name: '{name}'; must be a string" + assert isinstance(name, str), msg + # default error if module cannot be imported + err = f"Missing optional dependency '{name}'. {extra}" + module = type('module', (), {}) + # try to import the module + try: + module = importlib.import_module(name) + except (ImportError, ModuleNotFoundError) as exc: + if raise_exception: + raise ImportError(err) from exc + else: + logging.debug(err) + # return the module + return module + # PURPOSE: get the hash value of a file def get_hash( local: str | io.IOBase | pathlib.Path, @@ -265,6 +304,7 @@ def s3_client( response = urllib2.urlopen(request, timeout=timeout) cumulus = json.loads(response.read()) # get AWS client object + boto3 = import_dependency('boto3') client = boto3.client('s3', aws_access_key_id=cumulus['accessKeyId'], aws_secret_access_key=cumulus['secretAccessKey'], @@ -301,6 +341,7 @@ def s3_filesystem( response = urllib2.urlopen(request, timeout=timeout) cumulus = json.loads(response.read()) # get AWS file system session object + s3fs = import_dependency('s3fs') session = s3fs.S3FileSystem(anon=False, key=cumulus['accessKeyId'], secret=cumulus['secretAccessKey'], @@ -405,6 +446,7 @@ def generate_presigned_url( s3 presigned https url """ # generate a presigned URL for S3 object + boto3 = import_dependency('boto3') s3 = boto3.client('s3') try: response = s3.generate_presigned_url('get_object', @@ -1218,7 +1260,7 @@ def query_resources(**kwargs): - ``ATL14`` : land ice height - ``ATL15`` : land ice height change - release: str, default '001' + release: str, default '004' ICESat-2 data release version: str, default '01' ICESat-2 data version @@ -1256,7 +1298,7 @@ def query_resources(**kwargs): kwargs.setdefault('bucket', 'is2view') kwargs.setdefault('directory', None) kwargs.setdefault('product', 'ATL15') - kwargs.setdefault('release', '003') + kwargs.setdefault('release', '004') kwargs.setdefault('version', '01') kwargs.setdefault('cycles', None) kwargs.setdefault('region', 'AA') @@ -1294,7 +1336,7 @@ def query_resources(**kwargs): # verify inputs assert kwargs['asset'] in _assets assert kwargs['product'] in _products - assert kwargs['release'] in ('001', '002', '003') + assert kwargs['release'] in ('001', '002', '003', '004') if kwargs['cycles'] is not None: assert (len(kwargs['cycles']) == 2), 'cycles should be length 2' for r in kwargs['region']: @@ -1392,6 +1434,7 @@ def query_resources(**kwargs): cycles['001'] = (3, 11) cycles['002'] = (3, 14) cycles['003'] = (3, 18) + cycles['004'] = (3, 21) kwargs['cycles'] = cycles[kwargs['release']] # for each requested region for region in kwargs['region']: diff --git a/doc/environment.yml b/doc/environment.yml index 0a1b843..fe70dac 100644 --- a/doc/environment.yml +++ b/doc/environment.yml @@ -2,7 +2,7 @@ name: is2view-docs channels: - conda-forge dependencies: - - docutils<0.18 + - docutils - graphviz - ipywidgets - notebook diff --git a/doc/source/conf.py b/doc/source/conf.py index 88e1588..076a5de 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -14,19 +14,18 @@ # import sys import datetime # sys.path.insert(0, os.path.abspath('.')) -from pkg_resources import get_distribution +import importlib.metadata - -# -- Project information ----------------------------------------------------- - -project = 'IS2view' +# package metadata +metadata = importlib.metadata.metadata("IS2view") +project = metadata["Name"] year = datetime.date.today().year copyright = f"2022\u2013{year}, Tyler C. Sutterley" -author = 'Tyler Sutterley' +author = 'Tyler C. Sutterley' # The full version, including alpha/beta/rc tags # get semantic version from setuptools-scm -version = get_distribution("IS2view").version +version = metadata["version"] # append "v" before the version release = f"v{version}" diff --git a/doc/source/release_notes/release-v0.0.9.rst b/doc/source/release_notes/release-v0.0.9.rst new file mode 100644 index 0000000..10516af --- /dev/null +++ b/doc/source/release_notes/release-v0.0.9.rst @@ -0,0 +1,10 @@ +################## +`Release v0.0.9`__ +################## + +* ``refactor``: simplify and generalize mapping between observables and functionals (`#42 `_) +* ``feat``: minor updates for R004 (`#43 `_) +* ``docs``: bump ``docutils`` (`#43 `_) +* ``docs``: use ``importlib`` rather than ``pkg_resources`` (`#43 `_) + +.. __: https://github.com/tsutterley/IS2view/releases/tag/0.0.9 diff --git a/doc/source/user_guide/Recipes.rst b/doc/source/user_guide/Recipes.rst index f00c54a..cc55ff1 100644 --- a/doc/source/user_guide/Recipes.rst +++ b/doc/source/user_guide/Recipes.rst @@ -195,3 +195,10 @@ Requires optional ``geopandas`` and ``owslib`` dependencies. .. figure:: ../_assets/map.png :width: 600 :align: center + +Remove Image Service Layer from Map +################################### + +.. code-block:: python + + ds.leaflet.reset() diff --git a/notebooks/IS2-ATL14-Viewer.ipynb b/notebooks/IS2-ATL14-Viewer.ipynb index e06f2e1..5982313 100644 --- a/notebooks/IS2-ATL14-Viewer.ipynb +++ b/notebooks/IS2-ATL14-Viewer.ipynb @@ -29,7 +29,7 @@ "#### Set parameters for ATL14\n", "- Asset: Location to get the data\n", "- Directory: Working data directory\n", - "- Release: ATL14 data release (001, 002, 003)\n", + "- Release: ATL14 data release (001, 002, 003, 004)\n", "- Region: ATL14 data region (AA, A1, A2, A3, A4, CN, CS, GL, IS, RA, SV)\n", "- Format: ATL14 data format to read (nc, zarr)" ] @@ -182,23 +182,6 @@ " variable=IS2widgets.variable.value,\n", " )" ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Remove the image service layer from the map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.leaflet.reset()" - ] } ], "metadata": { diff --git a/notebooks/IS2-ATL15-Viewer.ipynb b/notebooks/IS2-ATL15-Viewer.ipynb index 5a9a2a8..f6713d3 100644 --- a/notebooks/IS2-ATL15-Viewer.ipynb +++ b/notebooks/IS2-ATL15-Viewer.ipynb @@ -29,7 +29,7 @@ "#### Set parameters for ATL15\n", "- Asset: Location to get the data\n", "- Directory: Working data directory\n", - "- Release: ATL15 data release (001, 002, 003)\n", + "- Release: ATL15 data release (001, 002, 003, 004)\n", "- Region: ATL15 data region (AA, A1, A2, A3, A4, CN, CS, GL, IS, RA, SV)\n", "- Resolution: ATL15 horizontal resolution (01km, 10km, 20km, 40km)\n", "- Group: ATL15 data group to read from file\n", @@ -129,9 +129,8 @@ " draw_control=True,\n", " attribution=False)\n", "# set plot attributes\n", - "IS2widgets.set_variables(ds)\n", + "IS2widgets.get_variables(ds)\n", "IS2widgets.set_atl15_defaults()\n", - "IS2widgets.set_time_steps(ds)\n", "wbox = IS2widgets.VBox([\n", " IS2widgets.variable,\n", " IS2widgets.timestep,\n", @@ -160,6 +159,7 @@ "source": [ "ds.leaflet.plot(m.map, lag=IS2widgets.lag,\n", " vmin=IS2widgets.vmin, vmax=IS2widgets.vmax,\n", + " group=IS2widgets.group.value,\n", " variable=IS2widgets.variable.value,\n", " cmap=IS2widgets.colormap,\n", " opacity=0.75,\n", @@ -192,21 +192,9 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, - "source": [ - "### Remove the image service layer from the map" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds.leaflet.reset()" - ] + "source": [] } ], "metadata": { diff --git a/version.txt b/version.txt index d169b2f..c5d54ec 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.0.8 +0.0.9