Skip to content

aggregate_channels loses per-probe metadata #4545

@h-mayorquin

Description

@h-mayorquin

Coming to this thinking on:
SpikeInterface/probeinterface#420
SpikeInterface/probeinterface#425

When a probe is attached to a recording via set_probe, _set_probes stores each probe's user-level metadata in two recording-level annotations: probes_info (a list where entry i is probe i's annotations dict, with keys like name, manufacturer, description) and one probe_{i}_planar_contour annotation per probe. aggregate_channels does not propagate either of these into the combined recording. probes_info is never copied at all, so even the first child's per-probe annotations disappear. probe_{i}_planar_contour annotations are only kept when every child happens to share the exact same contour; otherwise they are all dropped. The result is that combined.get_probegroup() exposes probes with empty annotations dicts and no planar contour, regardless of what was attached to the children.

import numpy as np
from probeinterface import generate_dummy_probe
from spikeinterface.core import generate_recording, aggregate_channels

def make_recording(probe_name, manufacturer, x_shift, contact_id_prefix):
    probe = generate_dummy_probe()
    probe.move([x_shift, 0.0])
    probe.annotate(name=probe_name, manufacturer=manufacturer)
    probe.set_device_channel_indices(np.arange(probe.get_contact_count()))
    probe.set_contact_ids([f"{contact_id_prefix}{i}" for i in range(probe.get_contact_count())])
    probe.create_auto_shape()
    rec = generate_recording(num_channels=probe.get_contact_count(), durations=[1.0], set_probe=False)
    return rec.set_probe(probe)

rec_A = make_recording("probe_A", "vendor_X", x_shift=0.0,    contact_id_prefix="a")
rec_B = make_recording("probe_B", "vendor_Y", x_shift=1000.0, contact_id_prefix="b")

print("rec_A annotation keys:", rec_A.get_annotation_keys())
print("rec_A probes_info:", rec_A.get_annotation("probes_info"))

combined = aggregate_channels([rec_A, rec_B])
print("combined annotation keys:", combined.get_annotation_keys())
print("combined probes_info:", combined.get_annotation("probes_info"))
print("combined probe_0_planar_contour:", combined.get_annotation("probe_0_planar_contour"))

Expected: the aggregate carries a probes_info list with one entry per child probe and probe_{i}_planar_contour annotations for each probe.

Observed on main:

rec_A annotation keys: ['is_filtered', 'name', 'probe_0_planar_contour', 'probes_info']
rec_A probes_info: [{'manufacturer': 'vendor_X', 'name': 'probe_A'}]
combined annotation keys: ['is_filtered']
combined probes_info: None
combined probe_0_planar_contour: None

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions