Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add set_probe method to BaseRecordingExtractorInterface #639

Merged
merged 29 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d2c465f
add set_probe to BaseRecordingExtractorInterface
magland Nov 10, 2023
3a27e52
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 10, 2023
9983099
Adjust comment in baserecordingextractorinterface.py
magland Nov 10, 2023
9037c96
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 11, 2023
e2b459e
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 13, 2023
8332459
cover set_probe with tests
magland Nov 14, 2023
30b4b40
Merge branch 'set-probe' of https://github.com/magland/neuroconv into…
magland Nov 14, 2023
d3f6e20
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2023
1b189ce
only test probe for select interfaces
magland Nov 14, 2023
f2259df
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 14, 2023
18776a7
remove debug line
magland Nov 14, 2023
b8f793b
Merge branch 'set-probe' of https://github.com/magland/neuroconv into…
magland Nov 14, 2023
1b9d94c
Merge branch 'main' into set-probe
bendichter Nov 20, 2023
893ec14
Update src/neuroconv/datainterfaces/ecephys/baserecordingextractorint…
magland Nov 20, 2023
b946c64
adjust _create_mock_probe()
magland Nov 20, 2023
645c2c0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 20, 2023
8cd1aa8
adjust _create_mock_probe() to be more realistic
magland Nov 20, 2023
de101e2
Merge branch 'set-probe' of https://github.com/magland/neuroconv into…
magland Nov 20, 2023
5dcc319
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 20, 2023
75aa8e1
fix _create_mock_probe()
magland Nov 20, 2023
d6cfc2f
Merge branch 'set-probe' of https://github.com/magland/neuroconv into…
magland Nov 20, 2023
6f5f9ba
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 21, 2023
9afd9a9
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 28, 2023
46f592d
adjust set_probe tests
magland Nov 28, 2023
d781a46
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 28, 2023
3f8cab5
RecordingExtractorInterfaceTestMixin: remove check for testing probe
magland Nov 28, 2023
e2298fa
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 28, 2023
69e5d94
recording extractor interface tests
magland Nov 28, 2023
5b3a999
Merge branch 'main' into set-probe
CodyCBakerPhD Nov 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
The name of the plane segmentation is used to determine which traces to add to the `Fluorescence` and `DfOverF` containers. [PR #632](https://github.com/catalystneuro/neuroconv/pull/632)
* Modify the filtering of traces to also filter out traces with empty values. [PR #649](https://github.com/catalystneuro/neuroconv/pull/649)
* Added tool function `get_default_dataset_configurations` for identifying and collecting all fields of an in-memory `NWBFile` that could become datasets on disk; and return instances of the Pydantic dataset models filled with default values for chunking/buffering/compression. [PR #569](https://github.com/catalystneuro/neuroconv/pull/569)
* Added `set_probe()` method to `BaseRecordingExtractorInterface`. [PR #639](https://github.com/catalystneuro/neuroconv/pull/639)

### Fixes
* Fixed GenericDataChunkIterator (in hdmf.py) in the case where the number of dimensions is 1 and the size in bytes is greater than the threshold of 1 GB. [PR #638](https://github.com/catalystneuro/neuroconv/pull/638)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,29 @@ def set_aligned_segment_starting_times(self, aligned_segment_starting_times: Lis
]
self.set_aligned_segment_timestamps(aligned_segment_timestamps=aligned_segment_timestamps)

def set_probe(self, probe, group_mode: Literal["by_shank", "by_probe"]):
"""
Set the probe information via a ProbeInterface object.

Parameters
----------
probe : probeinterface.Probe
The probe object.
group_mode : {'by_shank', 'by_probe'}
How to group the channels. If 'by_shank', channels are grouped by the shank_id column.
If 'by_probe', channels are grouped by the probe_id column.
This is a required parameter to avoid the pitfall of using the wrong mode.
"""
# Set the probe to the recording extractor
self.recording_extractor.set_probe(
probe,
in_place=True,
group_mode=group_mode,
Comment on lines +242 to +245
Copy link
Contributor

Choose a reason for hiding this comment

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

just one note: if the probe has less channels than the recording (e.g., you want to only select the A channels from an Intan recording), the set_probe(..., in_place=True) will fail.

We can't do anything about it, just something to keep in mind :)

Copy link
Member

Choose a reason for hiding this comment

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

@alejoe91 What would this represent in a real world case?

Would it be indicative of a bad probe definition by the user?

Or are there cases where the user might actually specify a probe correctly, but extra channels show up (possibly from auxiliary sources or a mistake in SI/neo)?

Copy link
Contributor

Choose a reason for hiding this comment

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

yes I think the second option is what I had in mind. You have a recording with Ephys + Aux channels and you might want to select ephys channels with the probe slicing

)
# Spike interface sets the "group" property
# But neuroconv allows "group_name" property to override spike interface "group" value
self.recording_extractor.set_property("group_name", self.recording_extractor.get_property("group").astype(str))
CodyCBakerPhD marked this conversation as resolved.
Show resolved Hide resolved

def align_by_interpolation(
self,
unaligned_timestamps: np.ndarray,
Expand Down
17 changes: 17 additions & 0 deletions src/neuroconv/tools/testing/data_interface_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
)
from neuroconv.utils import NWBMetaDataEncoder

from .mock_probes import generate_mock_probe


class DataInterfaceTestMixin:
"""
Expand Down Expand Up @@ -109,6 +111,13 @@ def test_conversion_as_lone_interface(self):
self.case = num
self.test_kwargs = kwargs
self.interface = self.data_interface_cls(**self.test_kwargs)
do_set_probe = isinstance(self.interface, BaseRecordingExtractorInterface)
if do_set_probe:
assert isinstance(self.interface, BaseRecordingExtractorInterface)
self.interface.set_probe(
generate_mock_probe(num_channels=self.interface.recording_extractor.get_num_channels()),
group_mode="by_shank",
)
CodyCBakerPhD marked this conversation as resolved.
Show resolved Hide resolved
self.check_metadata_schema_valid()
self.check_conversion_options_schema_valid()
self.check_metadata()
Expand Down Expand Up @@ -300,6 +309,14 @@ def check_read_nwb(self, nwbfile_path: str):
# are specified, which occurs during check_recordings_equal when there is only one channel
if self.nwb_recording.get_channel_ids()[0] != self.nwb_recording.get_channel_ids()[-1]:
check_recordings_equal(RX1=recording, RX2=self.nwb_recording, return_scaled=False)
for property_name in ["rel_x", "rel_y", "rel_z", "group"]:
if (
property_name in recording.get_property_keys()
or property_name in self.nwb_recording.get_property_keys()
):
assert_array_equal(
recording.get_property(property_name), self.nwb_recording.get_property(property_name)
)
if recording.has_scaled_traces() and self.nwb_recording.has_scaled_traces():
check_recordings_equal(RX1=recording, RX2=self.nwb_recording, return_scaled=True)

Expand Down
29 changes: 29 additions & 0 deletions src/neuroconv/tools/testing/mock_probes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from typing import List

import numpy as np


def generate_mock_probe(num_channels: int, num_shanks: int = 3):
import probeinterface as pi

# The shank ids will be 0, 0, 0, ..., 1, 1, 1, ..., 2, 2, 2, ...
shank_ids: List[int] = []
positions = np.zeros((num_channels, 2))
# ceil division
channels_per_shank = (num_channels + num_shanks - 1) // num_shanks
for i in range(num_shanks):
# x0, y0 is the position of the first electrode in the shank
x0 = 0
y0 = i * 200
for j in range(channels_per_shank):
if len(shank_ids) == num_channels:
break
shank_ids.append(i)
x = x0 + j * 10
y = y0 + (j % 2) * 10
positions[len(shank_ids) - 1] = x, y
probe = pi.Probe(ndim=2, si_units="um")
probe.set_contacts(positions=positions, shapes="circle", shape_params={"radius": 5})
probe.set_device_channel_indices(np.arange(num_channels))
probe.set_shank_ids(shank_ids)
return probe
2 changes: 1 addition & 1 deletion tests/test_on_data/test_recording_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ def check_extracted_metadata(self, metadata: dict):
assert len(metadata["Ecephys"]["Device"]) == 1
assert metadata["Ecephys"]["Device"][0]["name"] == "Neuronexus-32"
assert metadata["Ecephys"]["Device"][0]["description"] == "The ecephys device for the MEArec recording."
assert len(metadata["Ecephys"]["ElectrodeGroup"]) == 1
# assert len(metadata["Ecephys"]["ElectrodeGroup"]) == 1 # do not test this condition because in the test we are setting a mock probe
assert metadata["Ecephys"]["ElectrodeGroup"][0]["device"] == "Neuronexus-32"
assert metadata["Ecephys"]["ElectricalSeries"]["description"] == (
'{"angle_tol": 15, "bursting": false, "chunk_duration": 0, "color_noise_floor": 1, '
Expand Down
Loading