NeurodataWithoutBorders / nwbwidgets

Explore the hierarchical structure of NWB 2.0 files and visualize data with Jupyter widgets.
https://nwb-widgets.readthedocs.io/en/latest/
Other
48 stars 21 forks source link

[Bug]: render electrodes metadata table when column (e.g. 'x') is missing #278

Closed Diirkk closed 1 year ago

Diirkk commented 1 year ago

What happened?

Tried to render metadata table of a local .nwb file with extracellular electrophysiological recordings. When rendering the table in 'electrodes: metadata about extracellular electrodes' an error occurs (missing 'x'). Manual printing the table in command line works.

Steps to Reproduce

create nwb file with missing 'x' values in metadata.

nwbwidgets.nwb2widget(nwbfile)

click 'electrodes: metadata about extracellular electrodes' - 'table'

Traceback

AttributeError                            Traceback (most recent call last)
File ~\anaconda3\envs\NWB_exp\lib\site-packages\ipywidgets\widgets\widget.py:766, in Widget._handle_msg(self, msg)
    764         if 'buffer_paths' in data:
    765             _put_buffers(state, data['buffer_paths'], msg['buffers'])
--> 766         self.set_state(state)
    768 # Handle a state request.
    769 elif method == 'request_state':

File ~\anaconda3\envs\NWB_exp\lib\site-packages\ipywidgets\widgets\widget.py:643, in Widget.set_state(self, sync_data)
    638         self._send(msg, buffers=echo_buffers)
    640 # The order of these context managers is important. Properties must
    641 # be locked when the hold_trait_notification context manager is
    642 # released and notifications are fired.
--> 643 with self._lock_property(**sync_data), self.hold_trait_notifications():
    644     for name in sync_data:
    645         if name in self.keys:

File ~\anaconda3\envs\NWB_exp\lib\contextlib.py:142, in _GeneratorContextManager.__exit__(self, typ, value, traceback)
    140 if typ is None:
    141     try:
--> 142         next(self.gen)
    143     except StopIteration:
    144         return False

File ~\anaconda3\envs\NWB_exp\lib\site-packages\traitlets\traitlets.py:1502, in HasTraits.hold_trait_notifications(self)
   1500 for changes in cache.values():
   1501     for change in changes:
-> 1502         self.notify_change(change)

File ~\anaconda3\envs\NWB_exp\lib\site-packages\ipywidgets\widgets\widget.py:694, in Widget.notify_change(self, change)
    691     if name in self.keys and self._should_send_property(name, getattr(self, name)):
    692         # Send new state to front-end
    693         self.send_state(key=name)
--> 694 super().notify_change(change)

File ~\anaconda3\envs\NWB_exp\lib\site-packages\traitlets\traitlets.py:1517, in HasTraits.notify_change(self, change)
   1515 def notify_change(self, change):
   1516     """Notify observers of a change event"""
-> 1517     return self._notify_observers(change)

File ~\anaconda3\envs\NWB_exp\lib\site-packages\traitlets\traitlets.py:1564, in HasTraits._notify_observers(self, event)
   1561 elif isinstance(c, EventHandler) and c.name is not None:
   1562     c = getattr(self, c.name)
-> 1564 c(event)

File ~\anaconda3\envs\NWB_exp\lib\site-packages\nwbwidgets\base.py:130, in lazy_tabs.<locals>.on_selected_index(change)
    128 def on_selected_index(change):
    129     if isinstance(change.owner.children[change.new], widgets.HTML):
--> 130         children[change.new] = vis2widget(tabs_spec[change.new][1](node))
    131         change.owner.children = children

File ~\anaconda3\envs\NWB_exp\lib\site-packages\nwbwidgets\view.py:58, in show_dynamic_table(node, **kwargs)
     56 def show_dynamic_table(node, **kwargs) -> widgets.Widget:
     57     if node.name == "electrodes":
---> 58         return show_electrodes(node)
     59     return render_dataframe(node)

File ~\anaconda3\envs\NWB_exp\lib\site-packages\nwbwidgets\ecephys.py:85, in show_electrodes(electrodes_table)
     83 def show_electrodes(electrodes_table):
     84     in_dict = dict(table=render_dataframe)
---> 85     if np.isnan(electrodes_table.x[0]):  # position is not defined
     86         in_dict.update(electrode_groups=ElectrodeGroupsWidget)
     87     else:

AttributeError: 'DynamicTable' object has no attribute 'x'

Operating System

Windows

Python Version

3.9

Package Versions

No response

Code of Conduct

CodyCBakerPhD commented 1 year ago

Thanks @Diirkk!

I wasn't able to catch this one in the recent round of stress testing against IBL since they do encode that value

I'm guessing when PyNWB made those fields optional we failed to update the widgets to retrieve the column in a 'safe' manner from electrode tables where it might not exist

CodyCBakerPhD commented 1 year ago

Going to re-open this one until @Diirkk confirms that it completely solves the issue on their end

I just pushed a new release hopefully containing the fix, can you try running

pip install -U nwbwidgets
pip show nwbwidgets  # should now say '0.10.2'

in the environment you were running your notebook in and see if the issue is fixed?

Diirkk commented 1 year ago

The table renders smoothly now, thanks for resolving this so quickly!