SpikeInterface/probeinterface

Multiporbe recording

Closed this issue · 10 comments

mfvd commented

Hello,

I've been experimenting recording with two probes simultaneously and was wondering what could be the best option to deal with the channel layouts. Would it make sense to create a single probe object with 6 shanks (3 per probe) and sort the data by shank? At first glance this seems like a viable option.

It would be nice if someone could share their experiences with such layouts :)

Cheers,
Marcelo

Hi @mfvd

You can also create 2 probes in probeinterface, then make a probegroup and add them as separate spikeinterface groups with:

recording = recording.set_probe(probegroup, group_mode='by_probe')

This will load the two probes and assign different channel groups. Then you can use the spikeinterface.sorters.run_sorter_by_property() function to spike sort separate groups individually.

mfvd commented

Hi @alejoe91

Thanks for tour quick reply!

Just to make sure I understood correctly:
Would it still be possible to run the sorter by shank or would the group property now be the probe?

This group_mode have a role on how to set the group property.

By probe:

recording = recording.set_probe(probegroup, group_mode='by_probe')
print(recording.get_property('group')) # show 2 groups

By shank:

recording = recording.set_probe(probegroup, group_mode='by_shank')
print(recording.get_property('group')) # show 6 groups

Then internally, spikeinterface.sorters.run_sorter_by_property use the recording.split_by(self, property='group')

Note that you can use any property also for the splitting.

mfvd commented

Hi @samuelgarcia

Ok, that makes sense. I'll give it a try!

Thanks

mfvd commented

Hi @alejoe91 @samuelgarcia

I've tried Samuel's apporach and got the following error:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Input In [7], in <cell line: 31>()
     29 probegroup = pi.ProbeGroup()
     30 probegroup.add_probe(probe)
---> 31 probegroup.add_probe(probe2)
     33 # set recording channels to new probe>RHD map.
     34 # by shank to perform sorting by shank
     35 rec_probe = rec.set_probe(probegroup, 
     36                           group_mode='by_shank')

File /opt/anaconda3/envs/si_openephys/lib/python3.8/site-packages/probeinterface/probegroup.py:22, in ProbeGroup.add_probe(self, probe)
     18 """
     19 
     20 """
     21 if len(self.probes) > 0:
---> 22     self._check_compatible(probe)
     24 self.probes.append(probe)
     25 probe._probe_group = self

File /opt/anaconda3/envs/si_openephys/lib/python3.8/site-packages/probeinterface/probegroup.py:36, in ProbeGroup._check_compatible(self, probe)
     34 # check global channel maps
     35 self.probes.append(probe)
---> 36 self.check_global_device_wiring_and_ids()
     37 self.probes = self.probes[:-1]

File /opt/anaconda3/envs/si_openephys/lib/python3.8/site-packages/probeinterface/probegroup.py:188, in ProbeGroup.check_global_device_wiring_and_ids(self)
    185 valid_chans = chans[keep]['device_channel_indices']
    187 if valid_chans.size != np.unique(valid_chans).size:
--> 188     raise ValueError('channel device index are not unique across probes')
    190 # check unique ids for != ''
    191 all_ids = self.get_global_contact_ids()

ValueError: channel device index are not unique across probes

I set the device channel indices manually for each probe. Any idea of what error I've made?

manufacturer = 'cambridgeneurotech'
probe_name = 'ASSY-37-Fb'
probe = pi.get_probe(manufacturer, probe_name)

# Match to device (RHD headstage) map. In this case it was corrected because probeinterface was wrong.
device_channel_indices = [
    29, 19, 10, 18, 28, 30, 20, 17, 21, 31, 22, 16, 23, 27, 26, 25, 24, 7, 6, 5,
    4, 8, 9, 3, 11, 2, 12, 1, 13, 0, 14, 15]
# set channel ids based on probe map from cambridge site and RHD map.
probe.set_device_channel_indices(device_channel_indices)

### set info for PROBE_2 ###
probe2 = pi.get_probe(manufacturer, probe_name)
device_channel_indices_2 = [
    17, 20, 16, 21, 31, 23, 30, 24, 28, 19, 26, 8, 27, 10, 28, 11, 29, 12, 22, 7,
    25, 0, 4, 15, 5, 14, 9, 13, 6, 1, 3, 2]

device_channel_indices_2 = [element + 32 for element in device_channel_indices_2]
# set channel ids based on probe map from cambridge site and RHD map.
probe2.set_device_channel_indices(device_channel_indices_2)
# create and populate probegroup
probegroup = pi.ProbeGroup()
probegroup.add_probe(probe)
probegroup.add_probe(probe2)

rec_probe = rec.set_probe(probegroup, 
                          group_mode='by_shank')

As the error suggests, the device channel indices are not unique. You need to shift the second set by the number of channels in the first probe ;)

mfvd commented

Stupid error on my part...
I was certain device_channel_indices_2 = [element + 32 for element in device_channel_indices_2] was doing just that and did not spot a duplicate value in my list

thanks for the help @alejoe91

mfvd commented

I'm now having the following error:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
Input In [16], in <cell line: 41>()
     37 probegroup.add_probe(probe2)
     39 # set recording channels to new probe>RHD map.
     40 # by shank to perform sorting by shank
---> 41 rec_probe = rec.set_probe(probe=probegroup, 
     42                           group_mode='by_shank')

File /opt/anaconda3/envs/si_openephys/lib/python3.8/site-packages/spikeinterface/core/baserecording.py:325, in BaseRecording.set_probe(self, probe, group_mode, in_place)
    321 def set_probe(self, probe, group_mode='by_probe', in_place=False):
    322     """
    323     Wrapper on top on set_probes when there one unique probe.
    324     """
--> 325     assert isinstance(probe, Probe), 'must give Probe'
    326     probegroup = ProbeGroup()
    327     probegroup.add_probe(probe)

AssertionError: must give Probe

I set the probe indices and channel ids for the second probe and the values seem to be correct. Not sure what to do next.

### set info for PROBE_2 ###
probe2 = pi.get_probe(manufacturer, probe_name)
# Match to device (RHD headstage) map. In this case it was corrected because probeinterface was wrong.
device_channel_indices_2 = [
    17, 20, 16, 21, 31, 23, 30, 24, 18, 19, 26, 8, 27, 10, 28, 11, 29, 12, 22, 7,
    25, 0, 4, 15, 5, 14, 9, 13, 6, 1, 3, 2]

device_channel_indices_2_64 = [element + 32 for element in device_channel_indices_2]

probe2.set_device_channel_indices(device_channel_indices_2_64)

# set contact ids
contact_ids_2 = np.arange(33, 65, 1)
# set contact ids to account for second probe
probe2.set_contact_ids(contact_ids_2)

# create and populate probegroup
probegroup = pi.ProbeGroup()
probegroup.add_probe(probe)
probegroup.add_probe(probe2)

rec_probe = rec.set_probe(probegroup, 
                          group_mode='by_shank')

You need to do

rec_probe = rec.set_probegroup(probegroup, 
                          group_mode='by_shank')
mfvd commented