Skip to content

Commit

Permalink
feat: add widgets for making ATL08 PhoREAL requests
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutterley committed Nov 29, 2023
1 parent 1e5f07f commit 6fb5824
Showing 1 changed file with 210 additions and 10 deletions.
220 changes: 210 additions & 10 deletions clients/python/sliderule/ipysliderule.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,69 @@ def __init__(self, **kwargs):
)
self.yapc_weight.layout.display = 'none'

# ATL08 PhoREAL parameters
# slider for setting PhoREAL histogram bin size
self.phoreal_binsize = ipywidgets.FloatSlider(
value=1,
min=0.25,
max=10,
step=0.25,
description='PhoREAL Bin Size:',
description_tooltip="PhoREAL Bin Size: size of the vertical photon bin in meters",
disabled=False,
continuous_update=False,
orientation='horizontal',
readout=True,
readout_format='0.2f',
style=self.style,
)

# dropdown menu for setting PhoREAL geolocation algorithm
# mean - takes the average value across all photons in the segment
# median - takes the median value across all photons in the segment
# center - takes the halfway value calculated by the average of the first and last photon in the segment
phoreal_geolocation_list = ['mean','median','center']
self.phoreal_geolocation = ipywidgets.Dropdown(
options=phoreal_geolocation_list,
value='center',
description='PhoREAL Geolocation:',
description_tooltip=("PhoREAL Geolocation: method for calculating segment geolocation variables\n\t"
"mean: average value across all photons in the segment\n\t"
"median: median value across all photons in the segment\n\t"
"center: center of first and last photons in the segment"),
disabled=False,
style=self.style,
)

# checkbox for using PhoREAL absolute elevation
self.phoreal_abs_h = ipywidgets.Checkbox(
value=False,
description='PhoREAL use abs h',
description_tooltip=("PhoREAL use abs h: use absolute photon heights "
"instead of the normalized heights"),
disabled=False,
style=self.style,
)

# checkbox for using the PhoREAL ABoVE classifier
self.phoreal_above = ipywidgets.Checkbox(
value=False,
description='PhoREAL use ABoVE',
description_tooltip="PhoREAL use ABoVE: use the ABoVE photon classifier",
disabled=False,
style=self.style,
)

# checkbox for sending PhoREAL waveform
self.phoreal_waveform = ipywidgets.Checkbox(
value=False,
description='PhoREAL waveform',
description_tooltip=("PhoREAL waveform: send the photon height "
"histograms in addition to the vegetation statistics"),
disabled=False,
style=self.style,
)

# slider for setting length of ATL06-SR segment in meters
self.length = ipywidgets.IntSlider(
value=40,
Expand Down Expand Up @@ -449,7 +512,7 @@ def __init__(self, **kwargs):
description='Projection:',
description_tooltip=("Projection: leaflet map projection\n\t"
"Global: Web Mercator (EPSG:3857)\n\t"
"Alaska Polar Stereographic (EPSG:5936)\n\t"
"North: Alaska Polar Stereographic (EPSG:5936)\n\t"
"South: Polar Stereographic South (EPSG:3031)"),
disabled=False,
style=self.style,
Expand Down Expand Up @@ -679,10 +742,11 @@ def set_atl03_defaults(self):
"""sets the default widget parameters for ATL03 requests
"""
# default photon classifications
class_options = ['atl03','atl08','yapc']
self.classification.value = class_options
class_options = ['atl03', 'quality', 'atl08', 'yapc']
self.classification.options = class_options
self.classification.value = ['atl03', 'atl08', 'yapc']
# default ATL03 confidence
self.confidence.value = -2
self.confidence.value = -1
# set land class options
land_options = [
'atl08_noise',
Expand All @@ -708,8 +772,9 @@ def set_atl06_defaults(self):
"""sets the default widget parameters for ATL06 requests
"""
# default photon classifications
class_options = ['atl03','atl08']
self.classification.value = class_options
class_options = ['atl03', 'quality', 'atl08', 'yapc']
self.classification.options = class_options
self.classification.value = ['atl03', 'atl08']
# default ATL06-SR confidence
self.confidence.value = 4
# set land class options
Expand All @@ -726,6 +791,40 @@ def set_atl06_defaults(self):
self.file = copy.copy(self.atl06_filename)
self.savelabel.value = self.file

def set_atl08_defaults(self):
"""sets the default widget parameters for ATL08 requests
"""
# default photon classifications
class_options = ['atl03', 'quality', 'atl08']
self.classification.options = class_options
self.classification.value = ['atl08']
# default ATL08-SR confidence
self.confidence.value = -1
# set land class options
land_options = [
'atl08_ground',
'atl08_canopy',
'atl08_top_of_canopy',
]
self.land_class.value = land_options
# set default ATL08-SR length
self.length.value = 30
# set PhoREAL parameters
self.phoreal_binsize.value = 1.0
self.phoreal_geolocation.value = 'center'
self.phoreal_abs_h.value = False
self.phoreal_above.value = False
self.phoreal_waveform.value = False
# update variable list for ATL08-SR variables
variable_list = ['h_canopy', 'h_min_canopy', 'h_mean_canopy',
'h_max_canopy', 'canopy_openness', 'h_te_median',
'landcover', 'snowcover', 'solar_elevation', 'cycle', 'rgt']
self.variable.options = variable_list
self.variable.value = 'h_canopy'
# set default filename
self.file = copy.copy(self.atl08_filename)
self.savelabel.value = self.file

def atl03(self, **kwargs):
"""returns a list of widgets for SlideRule ATL03 requests
"""
Expand Down Expand Up @@ -783,6 +882,33 @@ def atl06(self, **kwargs):
self.sigma,
]

def atl08(self, **kwargs):
"""returns a list of widgets for SlideRule ATL08 requests
"""
kwargs.setdefault('display', 'advanced')
assert str(kwargs['display']).lower() in ['advanced','basic']
if (str(kwargs['display']).lower() == 'basic'):
return [
self.surface_type,
self.length,
self.phoreal_binsize,
]
else:
return [
self.classification,
self.surface_type,
self.confidence,
self.quality,
self.land_class,
self.phoreal_binsize,
self.phoreal_geolocation,
self.phoreal_abs_h,
self.phoreal_above,
self.phoreal_waveform,
self.length,
self.step,
]

@property
def time_start(self):
"""start time in ISO format
Expand Down Expand Up @@ -916,7 +1042,7 @@ def set_loadfile(self, sender):

@property
def atl03_filename(self):
"""default input and output file string
"""default input and output file string for ATL03 requests
"""
# get sliderule submission time
now = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
Expand All @@ -925,13 +1051,22 @@ def atl03_filename(self):

@property
def atl06_filename(self):
"""default input and output file string
"""default input and output file string for ATL06 requests
"""
# get sliderule submission time
now = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
args = (now, self.release.value)
return "ATL06-SR_{0}_{1}.h5".format(*args)

@property
def atl08_filename(self):
"""default input and output file string for ATL08 requests
"""
# get sliderule submission time
now = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
args = (now, self.release.value)
return "ATL08-SR_{0}_{1}.h5".format(*args)

@property
def format(self):
"""return the file format from file string
Expand Down Expand Up @@ -1074,6 +1209,46 @@ def build_atl06(self, **parms):
# return the parameter dictionary
return parms

# build sliderule ATL08 parameters using latest values from widget
def build_atl08(self, **parms):
"""Build a SlideRule parameters dictionary for making ATL08 requests
Parameters
----------
parms : dict, dictionary of SlideRule parameters to update
"""
# default parameters for all cases
# still return photon segments that fail checks
parms["pass_invalid"] = True
# length of ATL06-SR segment in meters
parms["len"] = self.length.value
# step distance for successive ATL06-SR segments in meters
parms["res"] = self.step.value
# PhoREAL parameters
parms["phoreal"] = {}
parms["phoreal"]["binsize"] = self.phoreal_binsize.value
parms["phoreal"]["geoloc"] = self.phoreal_geolocation.value
parms["phoreal"]["use_abs_h"] = self.phoreal_abs_h.value
parms["phoreal"]["send_waveform"] = self.phoreal_waveform.value
parms["phoreal"]["above_classifier"] = self.phoreal_above.value
# photon classification
# atl03 photon confidence level
if ('atl03' in self.classification.value):
# surface type: 0-land, 1-ocean, 2-sea ice, 3-land ice, 4-inland water
parms["srt"] = self.surface_type.index
# confidence level for PE selection
parms["cnf"] = self.confidence.value
# atl03 photon quality flags
if ('quality' in self.classification.value):
# confidence level for PE selection
parms["quality_ph"] = list(self.quality.value)
# atl08 land classification flags
if ('atl08' in self.classification.value):
# ATL08 land surface classifications
parms["atl08_class"] = list(self.land_class.value)
# return the parameter dictionary
return parms

# update values from widget using sliderule parameters dictionary
def set_values(self, parms):
"""Set widget values using a SlideRule parameters dictionary
Expand Down Expand Up @@ -1131,6 +1306,17 @@ def set_values(self, parms):
self.yapc_win_h.value = parms["yapc"]["win_h"]
if ('yapc' in parms.keys()) and ('win_x' in parms['yapc'].keys()):
self.yapc_win_x.value = parms["yapc"]["win_x"]
# PhoREAL parameters
if ('phoreal' in parms.keys()) and ('binsize' in parms['phoreal'].keys()):
self.phoreal_binsize.value = parms["phoreal"]["binsize"]
if ('phoreal' in parms.keys()) and ('geoloc' in parms['phoreal'].keys()):
self.phoreal_geolocation.value = parms["phoreal"]["geoloc"]
if ('phoreal' in parms.keys()) and ('use_abs_h' in parms['phoreal'].keys()):
self.phoreal_abs_h.value = parms["yapc"]["use_abs_h"]
if ('phoreal' in parms.keys()) and ('send_waveform' in parms['phoreal'].keys()):
self.phoreal_waveform.value = parms["phoreal"]["send_waveform"]
if ('phoreal' in parms.keys()) and ('above_classifier' in parms['phoreal'].keys()):
self.phoreal_above.value = parms["phoreal"]["above_classifier"]
# update values
return self

Expand Down Expand Up @@ -2205,6 +2391,14 @@ def default_atl06_fields():
return ['cycle', 'dh_fit_dx', 'gt', 'h_mean',
'h_sigma', 'rgt', 'rms_misfit', 'w_surface_window_final']

@staticmethod
def default_atl08_fields():
"""List of ATL08-SR tooltip fields
"""
return ['canopy_openness', 'cycle', 'gt', 'h_canopy',
'h_min_canopy', 'h_mean_canopy',
'h_max_canopy', 'h_te_median', 'rgt']

@staticmethod
def default_mosaic_fields(**kwargs):
kwargs.setdefault('with_flags', False)
Expand Down Expand Up @@ -2233,6 +2427,8 @@ def __init__(self, gdf):
# initialize data and colorbars
self.geojson = None
self.tooltip = None
self.tooltip_width = None
self.tooltip_height = None
self.fields = []
self.colorbar = None
# initialize hover control
Expand Down Expand Up @@ -2273,6 +2469,8 @@ def GeoData(self, m, **kwargs):
kwargs.setdefault('stride', None)
kwargs.setdefault('max_plot_points', 10000)
kwargs.setdefault('tooltip', True)
kwargs.setdefault('tooltip_height', "300px")
kwargs.setdefault('tooltip_width', "220px")
kwargs.setdefault('fields', [])
kwargs.setdefault('colorbar', True)
kwargs.setdefault('position', 'topright')
Expand Down Expand Up @@ -2331,6 +2529,8 @@ def GeoData(self, m, **kwargs):
self.tooltip = ipywidgets.HTML()
self.tooltip.layout.margin = "0px 20px 20px 20px"
self.tooltip.layout.visibility = 'hidden'
self.tooltip_height = kwargs['tooltip_height']
self.tooltip_width = kwargs['tooltip_width']
# create widget for hover tooltips
self.hover_control = ipyleaflet.WidgetControl(
widget=self.tooltip,
Expand Down Expand Up @@ -2361,8 +2561,8 @@ def handle_hover(self, feature, **kwargs):
self.tooltip.value = '<b>{0}:</b> {1}<br>'.format('id',feature['id'])
self.tooltip.value += '<br>'.join(['<b>{0}:</b> {1}'.format(field,
feature["properties"][field]) for field in self.fields])
self.tooltip.layout.width = "220px"
self.tooltip.layout.height = "300px"
self.tooltip.layout.width = self.tooltip_width
self.tooltip.layout.height = self.tooltip_height
self.tooltip.layout.visibility = 'visible'
self.map.add(self.hover_control)

Expand Down

0 comments on commit 6fb5824

Please sign in to comment.