SpikeInterface/probeinterface

Set plane_axes when make recording from nwb

Closed this issue · 7 comments

Hello, I am in the Frank lab at UCSF, and I use SpikeInterface as part of our NWB-DataJoint system (https://github.com/LorenFrankLab/spyglass). When I try to make a Recording from an NWB, I am getting a ValueError because I haven't specified plane_axes. We aren't sure of the recommended way to specify plane_axes. This occurs with SpikeInterface 0.94.0.dev0 and ProbeInterface 0.2.8, and it seems that this is the result of a recent change. Would it be possible to have an option in the NWB recording extractor for us to specify the plane axes for the probe contacts? Loren suggested @alejoe91 or @magland might be able to help us out with this. Thanks in advance!

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
File <timed eval>:1, in <module>

File ~/anaconda3/envs/nwb_datajoint_0330/lib/python3.8/site-packages/datajoint/autopopulate.py:189, in AutoPopulate.populate(self, suppress_errors, return_exception_objects, reserve_jobs, order, limit, max_calls, display_progress, processes, make_kwargs, *restrictions)
    187 if processes == 1:
    188     for key in tqdm(keys, desc=self.__class__.__name__) if display_progress else keys:
--> 189         error = self._populate1(key, jobs, **populate_kwargs)
    190         if error is not None:
    191             error_list.append(error)

File ~/anaconda3/envs/nwb_datajoint_0330/lib/python3.8/site-packages/datajoint/autopopulate.py:237, in AutoPopulate._populate1(self, key, jobs, suppress_errors, return_exception_objects, make_kwargs)
    235 self.__class__._allow_insert = True
    236 try:
--> 237     make(dict(key), **(make_kwargs or {}))
    238 except (KeyboardInterrupt, SystemExit, Exception) as error:
    239     try:

File ~/Src/nwb_datajoint/src/nwb_datajoint/spikesorting/spikesorting_recording.py:300, in SpikeSortingRecording.make(self, key)
    298 def make(self, key):
    299     sort_interval_valid_times = self._get_sort_interval_valid_times(key)
--> 300     recording = self._get_filtered_recording(key)
    301     recording_name = self._get_recording_name(key)
    303     tmp_key = {
    304         'nwb_file_name': key['nwb_file_name'],
    305         'interval_list_name': recording_name,
    306         'valid_times': sort_interval_valid_times
    307     }

File ~/Src/nwb_datajoint/src/nwb_datajoint/spikesorting/spikesorting_recording.py:394, in SpikeSortingRecording._get_filtered_recording(self, key)
    377 """Filters and references a recording
    378 * Loads the NWB file created during insertion as a spikeinterface Recording
    379 * Slices recording in time (interval) and space (channels);
   (...)
    390 recording: si.Recording
    391 """
    393 nwb_file_abs_path = Nwbfile().get_abs_path(key['nwb_file_name'])
--> 394 recording = se.read_nwb_recording(
    395     nwb_file_abs_path, load_time_vector=True)
    397 valid_sort_times = self._get_sort_interval_valid_times(key)
    398 # shape is (N, 2)

File ~/anaconda3/envs/nwb_datajoint_0330/lib/python3.8/site-packages/spikeinterface/extractors/nwbextractors.py:354, in read_nwb_recording(*args, **kwargs)
    353 def read_nwb_recording(*args, **kwargs):
--> 354     recording = NwbRecordingExtractor(*args, **kwargs)
    355     return recording

File ~/anaconda3/envs/nwb_datajoint_0330/lib/python3.8/site-packages/spikeinterface/extractors/nwbextractors.py:187, in NwbRecordingExtractor.__init__(self, file_path, electrical_series_name, load_time_vector, samples_for_rate_estimation)
    185 for prop_name, values in properties.items():
    186     if prop_name == "location":
--> 187         self.set_dummy_probe_from_locations(values)
    188     elif prop_name == "group":
    189         if np.isscalar(values):

File ~/anaconda3/envs/nwb_datajoint_0330/lib/python3.8/site-packages/spikeinterface/core/baserecording.py:494, in BaseRecording.set_dummy_probe_from_locations(self, locations, shape, shape_params, axes)
    492 ndim = locations.shape[1]
    493 probe = Probe(ndim=ndim)
--> 494 probe.set_contacts(locations, shapes=shape, shape_params=shape_params)
    495 probe.set_device_channel_indices(np.arange(self.get_num_channels()))
    497 if ndim == 3:

File ~/anaconda3/envs/nwb_datajoint_0330/lib/python3.8/site-packages/probeinterface/probe.py:177, in Probe.set_contacts(self, positions, shapes, shape_params, plane_axes, shank_ids)
    175 if plane_axes is None:
    176     if self.ndim == 3:
--> 177         raise ValueError('you need to give plane_axes')
    178     else:
    179         plane_axes = np.zeros((n, 2, self.ndim))

ValueError: you need to give plane_axes

Your recording have 3 dimension for probe description.
Sorter don't handle 2D.

You need to go to 2d

rec2d = rec3d.planarize("xy")  # or "xz" or "yz"
# and the
sorting = run_sorter('maintainsort4', rec2d)
print(sorting)

Hi Samuel. That makes sense, but the problem we're having is when we try to create the recording extractor, not when we try to sort. We need to be able to send the axes in to the recording extractor creation call, and we don't know how to do that.

Hi @lfrank

Is it from current master? Could you send me an nwb file that triggers the error so I can make sure that no bug arises?

Hi @alejoe91, yes, we are on the current master. I just emailed an nwb file for you to test whether this replicates on your end. Thanks so much.

Thanks for the file @acomrie

I was indeed able to reproduce the error and pushed a fix here: SpikeInterface/spikeinterface#584

Will give it a try once it has been merged. Thanks @alejoe91 !

I've just done a quick test so far, but that fix seems to be working for us. Thank you!