SpikeInterface / probeinterface

Python package to handle probe layout, geometry and wiring to device.
MIT License
53 stars 43 forks source link

Crash when loading prb file #81

Closed DradeAW closed 2 years ago

DradeAW commented 2 years ago

Hi,

I'm trying to load the geometry of my probe using probeinterface. However, it crashes because of this line, where the channel id is taken, but that doesn't work in out case:

https://github.com/SpikeInterface/probeinterface/blob/4c34a06293cd7a5602293829155a884d0f50a9fe/probeinterface/io.py#L451

Here is my prb file:

channel_groups = {
    0: {
        'channels': [10, 8, 25, 19, 23, 17, 11, 6, 22, 21, 7, 18, 20, 9, 16, 5],
        'geometry': [[0, 0], [-25, -12.5], [0, -25.0], [-25, -37.5], [0, -50.0], [-25, -62.5], [0, -75.0], [-25, -87.5], [0, -100.0], [-25, -112.5], [0, -125.0], [-25, -137.5], [0, -150.0], [-25, -162.5], [0, -175.0], [-25, -187.5]],
    'label': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],    
    },
    1: {
        'channels': [13, 4, 1, 27, 15, 12, 49, 2, 31, 29, 0, 14, 28, 3, 24, 26],
        'geometry': [[250, 0], [225, -12.5], [250, -25.0], [225, -37.5], [250, -50.0], [225, -62.5], [250, -75.0], [225, -87.5], [250, -100.0], [225, -112.5], [250, -125.0], [225, -137.5], [250, -150.0], [225, -162.5], [250, -175.0], [225, -187.5]],
    'label': [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
    },
    2: {
        'channels': [51, 58, 63, 37, 30, 50, 32, 60, 33, 35, 62, 48, 34, 61, 38, 36],
        'geometry': [[500, 0], [475, -12.5], [500, -25.0], [475, -37.5], [500, -50.0], [475, -62.5], [500, -75.0], [475, -87.5], [500, -100.0], [475, -112.5], [500, -125.0], [475, -137.5], [500, -150.0], [475, -162.5], [500, -175.0], [475, -187.5]],
    'label': [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47],
    },
    3: {
        'channels': [52, 54, 39, 45, 41, 47, 53, 56, 40, 43, 57, 44, 42, 55, 46, 59],
        'geometry': [[750, 0], [725, -12.5], [750, -25.0], [725, -37.5], [750, -50.0], [725, -62.5], [750, -75.0], [725, -87.5], [750, -100.0], [725, -112.5], [750, -125.0], [725, -137.5], [750, -150.0], [725, -162.5], [750, -175.0], [725, -187.5]],
    'label': [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63],
    }
}

Here is the crash report:

read_prb("arch.prb")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/users/nsr/wyngaard/.conda/envs/rapids/lib/python3.8/site-packages/probeinterface-0.2.5-py3.8.egg/probeinterface/io.py", line 443, in read_prb
    positions = np.array([group['geometry'][c] for c in chans],
  File "/users/nsr/wyngaard/.conda/envs/rapids/lib/python3.8/site-packages/probeinterface-0.2.5-py3.8.egg/probeinterface/io.py", line 443, in <listcomp>
    positions = np.array([group['geometry'][c] for c in chans],
IndexError: list index out of range

Is my prb file wrong, or is it a bug?

Thank you, Drade

samuelgarcia commented 2 years ago

The PRB is somehow a bit ambiguous. You should generate your probe directly with probeinterface object and save then with the internal format (json based).

In PRB, file 'channels' refer to the "channel index" of the device so the wiring. It is zeros based. This 'channels' will be set to device_channel_indices in the probe attributes.

samuelgarcia commented 2 years ago

Oh no. SOrry. there is a bug in the uimplementation of probeinterface. I will fix this soon. Sorry.

samuelgarcia commented 2 years ago

I understand now your problem. 'geometry' is supposed to be a dict in our implementation instead of a list of list.

So something like this:

channel_groups = {
    0: {
        'channels': [10, 8, 25, 19, 23, 17, 11, 6, 22, 21, 7, 18, 20, 9, 16, 5],
        'geometry': {
            10: [0, 0],
            8 : [-25, -12.5],
            25 : [0, -25.0],
         ...

in that case the acutal implementation is working.

Were did you get this PRB ? it sounds like a variant of PRB. The main problem with PRB format is that nobody never specify it really but many tools use it (klusta, spyking-circus, tridesclous, the old spikeinterface, ....)

It is the main reason why we introduce the probeinterface format with clear spec.

What I would do is to parse manually you pseudo-prb file and build by your own a good probegroup. It will be more reliable:

channel_groups = ....

probegroup = ProbeGroup()
for group_id, group in channel_groups.items():
    probe = Probe()

    probe.set_contacts(positions=np.array(group['geometry']),
                           shapes='circle', shape_params={'radius': 5})
    # probe.create_auto_shape(probe_type='tip')

    contact_ids = np.array(group['label'], dtype='S')
    probe.set_contact_ids(contact_ids)
    probe.set_device_channel_indices(group['channels'])
    probegroup.add_probe(probe)
DradeAW commented 2 years ago

I believe it came from Cambridge Neurotech with the probe.

Thank you for the answer, we'll try it!

DradeAW commented 2 years ago

Hi,

We've tested the code, and we're having some issues. Here is the code with the same arch.prb:

import probeinterface as pi
import numpy as np
import spikeinterface as si

recording = si.BinaryRecordingExtractor("/path/to/recording.dat", 30000, 64, np.int16)
execfile("/path/to/arch.prb") # Acquiring the channel_groups dict

probegroup = pi.ProbeGroup()
for group_id, group in channel_groups.items(): 
    probe = pi.Probe()

    probe.set_contacts(positions=np.array(group['geometry']),
                           shapes='circle', shape_params={'radius': 5})
    # probe.create_auto_shape(probe_type='tip')

    contact_ids = np.array(group['label'], dtype='S')
    probe.set_contact_ids(contact_ids)
    probe.set_device_channel_indices(group['channels'])
    probegroup.add_probe(probe)    

recording.set_probegroup(probegroup)
recording.get_probegroup()

We get the following error:

File "~/miniconda3/envs/projet/lib/python3.8/site-packages/spikeinterface-0.94.0.dev0-py3.8.egg/spikeinterface/core/baserecording.py", line 400, in get_probegroup
    raise ValueError('There is not Probe attached to recording. use set_probe(...)')

ValueError: There is not Probe attached to recording. use set_probe(...)

We are using the latest versions of spikeinterface and probeinterface.

samuelgarcia commented 2 years ago

You need to do recording_with_probe = recording.set_probegroup(probegroup) and then use recording_with_probe or recording = recording.set_probegroup(probegroup)

DradeAW commented 2 years ago

Ah yes, I feel kinda dumb ^^' I keep forgetting spikeinterface uses this king of setters.

Thank you!