diff --git a/src/coastseg/extract_shorelines_widget.py b/src/coastseg/extract_shorelines_widget.py index 50c9436c..e1c5f831 100644 --- a/src/coastseg/extract_shorelines_widget.py +++ b/src/coastseg/extract_shorelines_widget.py @@ -69,6 +69,7 @@ def __init__(self, extracted_shoreline_traitlet): self.extracted_shoreline_traitlet = extracted_shoreline_traitlet self.remove_callback = None self.load_callback = None + self.handle_exception = ipywidgets.CallbackDispatcher() # 2. Widget Creation @@ -83,12 +84,26 @@ def __init__(self, extracted_shoreline_traitlet): options=[], layout=ipywidgets.Layout(padding="0px", margin="0px"), ) - self.ROI_list_widget = ipywidgets.Dropdown( - description="Available ROIs", + self.roi_list_widget = ipywidgets.Dropdown( + description="ROI Ids", options=[], - layout=ipywidgets.Layout(padding="0px", margin="0px"), + layout=ipywidgets.Layout(width="60%", padding="0px", margin="0px"), + ) + # Define a lambda function that selects the first option in the options list + # select_first_option = lambda change: self.roi_list_widget.set_trait( + # "value", self.roi_list_widget.options[0] + # ) + select_first_option = ( + lambda change: self.roi_list_widget.set_trait( + "value", self.roi_list_widget.options[0] + ) + if self.roi_list_widget.options + else None ) + # Register the callback function with the observe method + self.roi_list_widget.observe(select_first_option, names="options") + # Buttons self.load_trash_button = ipywidgets.Button( description="", @@ -128,6 +143,8 @@ def __init__(self, extracted_shoreline_traitlet): self.undo_button.on_click(self.undo_button_clicked) self.empty_trash_button.on_click(self.delete_all_button_clicked) + # callback function for when a roi is selected + self.roi_list_widget.observe(self.on_roi_selected, names="value") # callback function for when a load shoreline item is selected self.load_list_widget.observe(self.on_load_selected, names="value") # callback function for when a trash item is selected @@ -162,6 +179,7 @@ def __init__(self, extracted_shoreline_traitlet): total_VBOX = ipywidgets.VBox( [ title_html, + self.roi_list_widget, load_instruction_box, load_list_vbox, trash_instruction_box, @@ -174,16 +192,16 @@ def __init__(self, extracted_shoreline_traitlet): super().__init__([total_VBOX]) - # def add_ROI_callback(self, callback: Callable[[List[str]], None]): - # """ - # Add a callback function to be called when a ROI ID is selected. + def add_ROI_callback(self, callback: Callable[[List[str]], None]): + """ + Add a callback function to be called when a ROI ID is selected. - # Parameters - # ---------- - # callback : function - # The function to be called when a ROI ID is selected. - # """ - # self.roi_selected_callback = callback + Parameters + ---------- + callback : function + The function to be called when a ROI ID is selected. + """ + self.roi_selected_callback = callback def add_load_callback(self, callback: Callable[[List[str]], None]): """ @@ -218,85 +236,119 @@ def add_remove_callback(self, callback: Callable[[List[str]], None]): """ self.remove_callback = callback - # def on_roi_selected(self, change: dict): - # """Callback function for when an ROI ID is selected""" - # # when the content sof the load list changes update the layer - # # self.roi_selected_callback(change["new"]) + def on_roi_selected(self, change: dict): + """Callback function for when an ROI ID is selected""" + try: + # when the content sof the load list changes update the layer + # clear the load and trash lists + self.load_list_widget.options = [] + self.trash_list_widget.options = [] + # call the callback function + self.roi_selected_callback(change["new"]) + except Exception as e: + self.handle_exception(e) def on_load_selected(self, change: dict): """Callback function for when a load shoreline item is selected""" - # when the content sof the load list changes update the layer - style = { - "color": "#001aff", # Outline color - "opacity": 1, # opacity 1 means no transparency - "weight": 3, # Width - "fillColor": "#001aff", # Fill color - "fillOpacity": 0.8, # Fill opacity. - "radius": 1, - } - layer_name = "extracted shoreline" - selected_items = self.load_list_widget.value - if selected_items and self.load_callback: - self.load_callback(selected_items, layer_name, style) - else: - # if no items are selected remove the shorelines from the map - if self.remove_callback: - self.remove_callback(layer_name) + try: + # when the content sof the load list changes update the layer + style = { + "color": "#001aff", # Outline color + "opacity": 1, # opacity 1 means no transparency + "weight": 3, # Width + "fillColor": "#001aff", # Fill color + "fillOpacity": 0.8, # Fill opacity. + "radius": 1, + } + layer_name = "extracted shoreline" + # get the selected shorelines + selected_items = self.load_list_widget.value + # get the selected ROI ID + selected_id = self.roi_list_widget.value + if selected_items and self.load_callback: + print("Calling the load callback") + self.load_callback( + selected_id, selected_items, layer_name, colormap="viridis" + ) + else: + # if no items are selected remove the shorelines from the map + if self.remove_callback: + self.remove_callback(layer_name) + except Exception as e: + self.handle_exception(e) def on_trash_selected(self, change: dict): """Callback function for when a trash item is selected""" - # this creates new a layer on the map that's styled red - style = { - "color": "#e82009", # Outline color - "opacity": 1, # opacity 1 means no transparency - "weight": 3, # Width - "fillColor": "#e82009", # Fill color - "fillOpacity": 0.8, # Fill opacity. - "radius": 1, - } - selected_items = self.trash_list_widget.value - layer_name = "delete" - if selected_items and self.load_callback: - self.load_callback(selected_items, layer_name, style) - else: - # if no items are selected remove the shorelines from the map - if self.remove_callback: - self.remove_callback(layer_name) + try: + # this creates new a layer on the map that's styled red + style = { + "color": "#e82009", # Outline color + "opacity": 1, # opacity 1 means no transparency + "weight": 3, # Width + "fillColor": "#e82009", # Fill color + "fillOpacity": 0.8, # Fill opacity. + "radius": 1, + } + # get the selected shorelines + selected_items = self.trash_list_widget.value + layer_name = "delete" + # get the selected ROI ID + selected_id = self.roi_list_widget.value + if selected_items and self.load_callback: + self.load_callback( + selected_id, selected_items, layer_name, colormap="Reds" + ) + else: + # if no items are selected remove the shorelines from the map + if self.remove_callback: + self.remove_callback(layer_name) + except Exception as e: + self.handle_exception(e) def trash_button_clicked(self, btn): """Callback function for when the trash button is clicked""" # get selected shorelines out of all the available shorelines - selected_items = self.load_list_widget.value - print(selected_items) - # add - self.extracted_shoreline_traitlet.trash_list = ( - self.extracted_shoreline_traitlet.trash_list + list(selected_items) - ) - # remove the items from the load_list - self.extracted_shoreline_traitlet.load_list = list( - set(self.extracted_shoreline_traitlet.load_list) - set(selected_items) - ) + try: + selected_items = self.load_list_widget.value + # add the items to the trash list + self.extracted_shoreline_traitlet.trash_list = ( + self.extracted_shoreline_traitlet.trash_list + list(selected_items) + ) + # remove the items from the load_list + self.extracted_shoreline_traitlet.load_list = list( + set(self.extracted_shoreline_traitlet.load_list) - set(selected_items) + ) + except Exception as e: + self.handle_exception(e) def undo_button_clicked(self, btn): """Callback function for when the undo button is clicked""" - selected_items = self.trash_list_widget.value - self.extracted_shoreline_traitlet.trash_list = list( - set(self.extracted_shoreline_traitlet.trash_list) - set(selected_items) - ) - # add the items back to the load_list - self.extracted_shoreline_traitlet.load_list = list( - self.extracted_shoreline_traitlet.load_list + list(selected_items) - ) + try: + selected_items = self.trash_list_widget.value + self.extracted_shoreline_traitlet.trash_list = list( + set(self.extracted_shoreline_traitlet.trash_list) - set(selected_items) + ) + # add the items back to the load_list + self.extracted_shoreline_traitlet.load_list = list( + self.extracted_shoreline_traitlet.load_list + list(selected_items) + ) + except Exception as e: + self.handle_exception(e) def delete_all_button_clicked(self, btn): """Callback function for when the delete all button is clicked""" - selected_items = self.trash_list_widget.value - self.extracted_shoreline_traitlet.trash_list = list( - set(self.trash_list_widget.options) - set(selected_items) - ) - self.extracted_shoreline_traitlet.load_list = list( - set(self.load_list_widget.options) - set(selected_items) - ) - if self.remove_all_callback: - layer_name = "delete" - self.remove_all_callback(layer_name, selected_items) + try: + selected_items = self.trash_list_widget.options + self.extracted_shoreline_traitlet.trash_list = [] + # remove the deleted items from the load list + self.extracted_shoreline_traitlet.load_list = list( + set(self.load_list_widget.options) - set(selected_items) + ) + # get the selected ROI ID + selected_id = self.roi_list_widget.value + + if self.remove_all_callback: + layer_name = "delete" + self.remove_all_callback(layer_name, selected_id, selected_items) + except Exception as e: + self.handle_exception(e)