Enhance probegroup API#1
Conversation
Not sure this is a good stuff, this contact order is tricky and should be internal only for the corner cases.
We should maintain the order requested no ?
Thank you, let me check in detail it was tricky than it appear. |
|
|
||
| return probegroup | ||
|
|
||
| # TODO: this should only return the device_channel_indices, not the probe_index!!! |
|
@samuelgarcia done what we discussed:
|
|
Thanks, this addresses most of the concerns. One point on index-versus-ids for the Probes. I am sympathetic to @samuelgarcia: we seldom have good ids for Probes. The natural one is the serial number, often unavailable and too verbose to be human-readable, so at first glance an index is the nicer handle. The problem is what Take three Probes:
Now Option 1, re-index to stay contiguous. After
ProbeC went
ProbeB lands at Option 2, leave a gap to keep each number. After
This keeps identity but defeats the index: it stops being a contiguous
or append
There is no clean choice because the index is asked to be two things at once: a position (contiguous, reflects the structure) and a name (stable across operations). So reaching for the index because ids are not human-readable is a cure that costs more than the disease: the id ergonomics are mildly annoying, but the index brings a real ambiguity into exactly the operations that started this. Giving Probes ids keeps identity stable through both and is easier to reason about. |
So the |
| args = 1e7, 1e8 | ||
| # 3rd argument has to be the number of probes | ||
| args = args[:2] + (len(self.probes),) | ||
| def check_global_device_wiring_and_ids(self) -> None: |
| if probe_id_annotation is not None: | ||
| probe_id = probe_id_annotation | ||
| else: | ||
| probe_id = f"{len(self._probes)}" |
There was a problem hiding this comment.
| probe_id = f"{len(self._probes)}" | |
| existing_int_ids = [int(pid) for pid in self._probe_ids if pid.isdigit()] | |
| probe_id = str(max(existing_int_ids, default=-1) + 1) |
The default probe id comes from the probe count (f"{len(self._probes)}"), which assumes ids stay contiguous. Once a slice leaves a gap the count points back at an id that still exists.
Now (current, len):
start: ["0", "1", "2"]
select_probes(["0", "2"]): ["0", "2"] ("1" dropped, "2" kept)
add_probe(p): len = 2 -> "2" -> collides with existing "2", raises
With the proposal (max + 1):
start: ["0", "1", "2"]
select_probes(["0", "2"]): ["0", "2"] ("1" dropped, "2" kept)
add_probe(p): max(0, 2) + 1 = "3" -> ["0", "2", "3"]
Non-numeric probe ids, with the proposal:
start: ["left", "right"]
add_probe(p): no numeric ids, max(default=-1) + 1 = "0" -> ["left", "right", "0"]
max(existing numeric ids) + 1 is gap-proof, never recycles a removed probe's id, and the generated digit-string can never collide with a non-numeric name.
h-mayorquin
left a comment
There was a problem hiding this comment.
LGTM after all the changes, I added a bunch of suggestions. Feel free to ignore, I can take them later as a separate PR if you guys want expediency.
|
@h-mayorquin addressed all :) Note that the setter is gone, so this was not relevant: #1 (comment) |
@samuelgarcia @h-mayorquin
Some changes on top of #446 that start addressing the points raised here + in #447:
New / changed
set_global_contact_order: helper function to set private variableselect_contacts(contact_ids=..., probe_ids=...)— identifier-based selection (either or both), as proposed in Slice Probe and ProbeGroup by stable identifiers, not positional integers SpikeInterface/probeinterface#447. Layered on top ofget_slice.probe_idsupport —add_probe(probe, probe_id=...), aprobe_idslist, andset_probe_ids(). Defaults toprobe_1,probe_2, …get_slicenow propagates metadata — probe annotations are mapped to the correct sliced probe (robust to skipped probes) andprobe_idsare carried over. This fixes the "annotations should be handled, not left as a TODO" comment.__repr__, extended examples (ex_03,ex_05) and grew the test suite (now coversset_global_contact_order,select_contactsin all modes, andget_sliceannotation/probe_idpropagation)..tolist()and theset_global_device_channel_indicesdocstring rename.Re SpikeInterface#447
select_contactsis the identifier-based API #447 asks for, so this is a first step in that direction. I keptget_sliceas the internal mechanism rather than removing it, but this is not in the docs