When select_channels drops all channels of some probe from a multi-probe recording, the per-probe annotations (probes_info and each probe_{i}_planar_contour) are carried over verbatim rather than pruned to match the surviving probes. get_probegroup then pairs those stale annotations with the surviving probes by enumeration order, so after dropping probe A from a recording, the one surviving probe ends up labeled with probe A's name, manufacturer, and planar contour even though its channels all came from probe B. Unlike the aggregate_channels case where probe metadata is dropped outright, here it is retained but mis-attributed, which is harder to notice.
import numpy as np
from probeinterface import generate_dummy_probe, ProbeGroup
from spikeinterface.core import generate_recording
def make_probe(name, manufacturer, x_shift, contact_id_prefix):
p = generate_dummy_probe()
p.move([x_shift, 0.0])
p.annotate(name=name, manufacturer=manufacturer)
p.set_contact_ids([f"{contact_id_prefix}{i}" for i in range(p.get_contact_count())])
p.create_auto_shape()
return p
p_A = make_probe("probe_A", "vendor_X", 0.0, "a")
p_B = make_probe("probe_B", "vendor_Y", 1000.0, "b")
pg = ProbeGroup()
pg.add_probe(p_A)
pg.add_probe(p_B)
dci = np.arange(pg.get_contact_count())
p_A.set_device_channel_indices(dci[:p_A.get_contact_count()])
p_B.set_device_channel_indices(dci[p_A.get_contact_count():])
rec = generate_recording(num_channels=pg.get_contact_count(), durations=[1.0], set_probe=False)
rec = rec.set_probegroup(pg)
# Drop all of probe A's channels, keep only probe B
keep_ids = rec.get_channel_ids()[p_A.get_contact_count():]
sliced = rec.select_channels(keep_ids)
probes = sliced.get_probegroup().probes
print(f"n probes: {len(probes)}")
for i, p in enumerate(probes):
print(f" probe {i}: name={p.annotations.get('name')}, manufacturer={p.annotations.get('manufacturer')}")
Expected: the surviving probe is labeled with probe B's annotations.
Observed on main:
n probes: 1
probe 0: name=probe_A, manufacturer=vendor_X
The only surviving probe carries probe_A's name and manufacturer even though all its channels came from probe B. The same misattribution applies to probe_planar_contour. If the slice instead keeps at least one channel from every probe, the positions of the surviving probes coincide with the original probe indices and the annotations line up correctly — the bug is specific to full-probe drops.
When
select_channelsdrops all channels of some probe from a multi-probe recording, the per-probe annotations (probes_infoand eachprobe_{i}_planar_contour) are carried over verbatim rather than pruned to match the surviving probes.get_probegroupthen pairs those stale annotations with the surviving probes by enumeration order, so after dropping probe A from a recording, the one surviving probe ends up labeled with probe A's name, manufacturer, and planar contour even though its channels all came from probe B. Unlike theaggregate_channelscase where probe metadata is dropped outright, here it is retained but mis-attributed, which is harder to notice.Expected: the surviving probe is labeled with probe B's annotations.
Observed on
main:The only surviving probe carries
probe_A's name and manufacturer even though all its channels came from probe B. The same misattribution applies toprobe_planar_contour. If the slice instead keeps at least one channel from every probe, the positions of the surviving probes coincide with the original probe indices and the annotations line up correctly — the bug is specific to full-probe drops.