Skip to content

Use ProbeGroup object instead of contact_vector property and set_probe/probegroup from select_channels_with_probe/probegroup#4465

Merged
alejoe91 merged 37 commits into
SpikeInterface:mainfrom
alejoe91:probegroup
Jul 3, 2026
Merged

Use ProbeGroup object instead of contact_vector property and set_probe/probegroup from select_channels_with_probe/probegroup#4465
alejoe91 merged 37 commits into
SpikeInterface:mainfrom
alejoe91:probegroup

Conversation

@alejoe91

@alejoe91 alejoe91 commented Mar 24, 2026

Copy link
Copy Markdown
Member

Updated 7/1/26

@h-mayorquin after discussing with @samuelgarcia, we decided that 1 PR is ok

After SpikeInterface/probeinterface#446, we can go all in on the use of ProbeGroup instead of contact_vector, since the use case with interleaved contacts after device channel indices slicing is handled gracefully by the new _global_contact_order array, stored in the probegroup dictionary.
Now the recording has a _probegroup attribute, which is propagated as metadata. The probegroup.get_slice takes care of all metadata propagation.
In this refactoring, the duplicated location property has also been dropped.

Note that this implementation is alternative to what is proposed in #4553 and implemented in #4548 : here we keep a ProbeGroup object attached to the recording, after sorting it by device_channel_indices, instead of adding a wiring property. You lose the original probe contact order, but we argue that the contacts in a probegroup do not really have a "default" order, but are rather a set of contacts that become ordered when wired (see #3498).

Some additional points:

Tests for aggregation/slicing

Added more tests for aggregation/slicing behavior and metadata propagation

Fixes #4545 #4546 #4547 #4549 #4553

Tests for backward compatibility

Added a test for bakward compatibility, which saves a recording to binary/zarr/JSON/pickle with v0.102/3/4.* and reloads it with the current version to check that the probegroup is reloaded correctly.
This way we check that the new handle_extractor_backward_compatibility() handles all cases!

set_probe/probegroup versus select_channels_with_probe/probegroup

This PR refactors the set_probe function to address several issues:

  • set_probe/probegroup: now are only in place (the not in place is deprecated, but will be removed in 0.106.0): these functions now require that the connected contacts have the same length as the number of channels.
  • added select_channels_with_probe/probegroup to handle the slicing of recordings with probes.

Fixes #2193

@alejoe91 alejoe91 added this to the 0.105.0 milestone Mar 24, 2026
@alejoe91 alejoe91 added the core Changes to core module label Mar 24, 2026
Comment thread src/spikeinterface/core/base.py Outdated
Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
Comment thread src/spikeinterface/core/channelslice.py Outdated
Co-authored-by: Alessio Buccino <alejoe9187@gmail.com>
@alejoe91 alejoe91 marked this pull request as draft March 25, 2026 08:53
@alejoe91 alejoe91 marked this pull request as ready for review March 25, 2026 14:01
)
# check that multiple probes are non-overlapping
all_probes = recording.get_probegroup().probes
check_probe_do_not_overlap(all_probes)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is removed because when we split_by and aggregate probes might overlap

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was important.
At least lets make a flag to control this.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added it back

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this needs to be removed. The issue is that before the aggregation was creating a single new probe, now it keeps a probegroup

@h-mayorquin

Copy link
Copy Markdown
Collaborator

I would like to take a look to this. I can do it this week.

Comment thread src/spikeinterface/core/baserecording.py
Comment thread src/spikeinterface/core/baserecordingsnippets.py
Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
Comment on lines +266 to +267
)
raise ValueError(error_msg)

new_channel_ids = self.get_channel_ids()[device_channel_indices]
probe_as_numpy_array = probe_as_numpy_array[order]
probe_as_numpy_array["device_channel_indices"] = np.arange(probe_as_numpy_array.size, dtype="int64")

# create recording : channel slice or clone or self
if in_place:
if not np.array_equal(new_channel_ids, self.get_channel_ids()):
raise Exception("set_probe(inplace=True) must have all channel indices")
sub_recording = self
else:
if np.array_equal(new_channel_ids, self.get_channel_ids()):
sub_recording = self.clone()
if len(keep_indices) == 0:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can help the user more with raiseing here instead of havin an empty rec/probe

Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
Comment thread src/spikeinterface/core/tests/test_baserecording.py Outdated
@alejoe91 alejoe91 changed the title Separate set_probe/probegroup from select_channels_with_probe/probegroup Use ProbeGroup object instead of contact_vector property and set_probe/probegroup from select_channels_with_probe/probegroup Jul 2, 2026
@alejoe91

alejoe91 commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

@samuelgarcia @h-mayorquin now this is ready and final

@h-mayorquin h-mayorquin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

The backward-compat fixtures cover single-probe (sequential and shuffled) and a contiguous two-probe recording, but not an interleaved multi-probe one (two probes whose device_channel_indices alternate, e.g. [0, 2, 4, 6, 1, 3, 5, 7]). That case does work on this branch, I checked it reloads with the correct per-channel locations thanks to _global_contact_order, but nothing tests it, so a future change to the reconstruction / get_slice / _global_contact_order could silently scramble channel-to-location alignment on load without CI noticing.

I am covering that in #4636 though.

Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
Comment thread src/spikeinterface/core/baserecordingsnippets.py Outdated
@alejoe91

alejoe91 commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

LGTM

The backward-compat fixtures cover single-probe (sequential and shuffled) and a contiguous two-probe recording, but not an interleaved multi-probe one (two probes whose device_channel_indices alternate, e.g. [0, 2, 4, 6, 1, 3, 5, 7]). That case does work on this branch, I checked it reloads with the correct per-channel locations thanks to _global_contact_order, but nothing tests it, so a future change to the reconstruction / get_slice / _global_contact_order could silently scramble channel-to-location alignment on load without CI noticing.

I am covering that in #4636 though.

Added the interleaved probegroup case. We cna unify backward compatibility tests later following #4636

check_probe_do_not_overlap(probegroup.probes)

probegroup_sorted = self._get_probegroup_based_on_device_channel_indices(probegroup)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a checker that the deevice_channel_indices is equal to np.arange() here.

Because nothing prevent to have somethign like this [0, 2, 5, 9]

Comment thread src/spikeinterface/core/baserecordingsnippets.py
Comment thread src/spikeinterface/core/baserecordingsnippets.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core Changes to core module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

aggregate_channels loses per-probe metadata set_probe behavior for RecordingExtractors

5 participants