Skip to content

[BUG] Removing all data from 2D viewer results in traceback #3486

@rosteen

Description

@rosteen

Jdaviz component

Specviz2d

Description

If you remove all of the data from the 2D viewer, the spectral extraction plugin raises an error:

AttributeError                            Traceback (most recent call last)
File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/ipyvue/VueTemplateWidget.py:60](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/ipyvue/VueTemplateWidget.py#line=59), in Events._handle_event(self, _, content, buffers)
     58     getattr(self, "vue_" + event)(data, buffers)
     59 else:
---> 60     getattr(self, "vue_" + event)(data)

File [~/projects/jdaviz/jdaviz/configs/default/plugins/data_menu/data_menu.py:540](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/configs/default/plugins/data_menu/data_menu.py#line=539), in DataMenu.vue_remove_from_viewer(self, *args)
    539 def vue_remove_from_viewer(self, *args):
--> 540     self.remove_from_viewer()

File [~/projects/jdaviz/jdaviz/configs/default/plugins/data_menu/data_menu.py:537](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/configs/default/plugins/data_menu/data_menu.py#line=536), in DataMenu.remove_from_viewer(self)
    535     self.set_layer_visibility(layer, visible=False)
    536 else:
--> 537     self.app.remove_data_from_viewer(self.viewer_id, layer)

File [~/projects/jdaviz/jdaviz/app.py:1732](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/app.py#line=1731), in Application.remove_data_from_viewer(self, viewer_reference, data_label)
   1726 viewer._layers_with_defaults_applied = [layer_info for layer_info in viewer._layers_with_defaults_applied  # noqa
   1727                                         if layer_info['data_label'] != data.label]  # noqa
   1729 remove_data_message = RemoveDataMessage(data, viewer,
   1730                                         viewer_id=viewer_id,
   1731                                         sender=self)
-> 1732 self.hub.broadcast(remove_data_message)

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/glue/core/hub.py:225](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/glue/core/hub.py#line=224), in Hub.broadcast(self, message)
    223 logging.getLogger(__name__).info("Broadcasting %s", message)
    224 for subscriber, handler in self._find_handlers(message):
--> 225     handler(message)

File [~/projects/jdaviz/jdaviz/core/template_mixin.py:3857](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/core/template_mixin.py#line=3856), in DatasetSelect._update_items(self, msg)
   3854 manual_items = [{'label': label} for label in self.manual_options]
   3855 self.items = manual_items + [_dc_to_dict(data) for data in self.app.data_collection
   3856                              if self._is_valid_item(data)]
-> 3857 self._apply_default_selection()
   3858 # future improvement: only clear cache if the selected data entry was changed?
   3859 self._clear_cache(*self._cached_properties)

File [~/projects/jdaviz/jdaviz/core/template_mixin.py:1098](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/core/template_mixin.py#line=1097), in SelectPluginComponent._apply_default_selection(self, skip_if_current_valid)
   1096 default_empty = [] if self.is_multiselect else ''
   1097 if self.default_mode == 'first':
-> 1098     self.selected = self.labels[0] if len(self.labels) else default_empty
   1099 elif self.default_mode == 'default_text':
   1100     self.selected = self._default_text if self._default_text else default_empty

File [~/projects/jdaviz/jdaviz/core/template_mixin.py:767](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/core/template_mixin.py#line=766), in BasePluginComponent.__setattr__(self, attr, value, force_super)
    764 if attr[0] == '_' or force_super or attr not in self._plugin_traitlets.keys():
    765     return super().__setattr__(attr, value)
--> 767 return setattr(self._plugin, self._plugin_traitlets.get(attr), value)

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py:716](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py#line=715), in TraitType.__set__(self, obj, value)
    714 if self.read_only:
    715     raise TraitError('The "%s" trait is read-only.' % self.name)
--> 716 self.set(obj, value)

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py:706](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py#line=705), in TraitType.set(self, obj, value)
    702     silent = False
    703 if silent is not True:
    704     # we explicitly compare silent to True just in case the equality
    705     # comparison above returns something other than True[/False](http://localhost:8888/False)
--> 706     obj._notify_trait(self.name, old_value, new_value)

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py:1513](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py#line=1512), in HasTraits._notify_trait(self, name, old_value, new_value)
   1512 def _notify_trait(self, name: str, old_value: t.Any, new_value: t.Any) -> None:
-> 1513     self.notify_change(
   1514         Bunch(
   1515             name=name,
   1516             old=old_value,
   1517             new=new_value,
   1518             owner=self,
   1519             type="change",
   1520         )
   1521     )

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/ipywidgets/widgets/widget.py:701](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/ipywidgets/widgets/widget.py#line=700), in Widget.notify_change(self, change)
    698     if name in self.keys and self._should_send_property(name, getattr(self, name)):
    699         # Send new state to front-end
    700         self.send_state(key=name)
--> 701 super().notify_change(change)

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py:1525](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py#line=1524), in HasTraits.notify_change(self, change)
   1523 def notify_change(self, change: Bunch) -> None:
   1524     """Notify observers of a change event"""
-> 1525     return self._notify_observers(change)

File [~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py:1568](http://localhost:8888/lab/tree/~/opt/anaconda3/envs/viz_dev/lib/python3.13/site-packages/traitlets/traitlets.py#line=1567), in HasTraits._notify_observers(self, event)
   1565 elif isinstance(c, EventHandler) and c.name is not None:
   1566     c = getattr(self, c.name)
-> 1568 c(event)

File [~/projects/jdaviz/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.py:393](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/configs/specviz2d/plugins/spectral_extraction/spectral_extraction.py#line=392), in SpectralExtraction._trace_dataset_selected(self, msg)
    389 if not hasattr(self, 'trace_dataset'):
    390     # happens when first initializing plugin outside of tray
    391     return
--> 393 width = self.trace_dataset.get_selected_spectrum(use_display_units=True).shape[0]
    394 # estimate the pixel number by taking the median of the brightest pixel index in each column
    395 trace_flux = self.trace_dataset.get_selected_spectrum(use_display_units=True).flux

File [~/projects/jdaviz/jdaviz/core/template_mixin.py:3721](http://localhost:8888/lab/tree/~/projects/jdaviz/jdaviz/core/template_mixin.py#line=3720), in DatasetSelect.get_selected_spectrum(self, use_display_units)
   3719 def get_selected_spectrum(self, use_display_units=True):
   3720     # retrieves the 1d spectrum
-> 3721     if len(self.selected_obj.shape) == 3:
   3722         # then this is a cube, but we want the 1D spectrum,
   3723         # so we can pass through the Spectral Extraction plugin
   3724         if self.plugin.config != 'cubeviz':
   3725             raise ValueError("extracting a spectrum from a cube only supported in cubeviz")

AttributeError: 'NoneType' object has no attribute 'shape'

How to Reproduce

  1. Run Specviz2D example notebook
  2. Remove the data from the 2D viewer

Expected behavior

No response

Browser

No response

Jupyter

No response

Software versions

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageIssue opened via template and needs triaging

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions