From 6d4f8a0b932433632138bc75fd4afc04ffa3d267 Mon Sep 17 00:00:00 2001 From: Kyu Hyun Lee Date: Fri, 28 Jul 2023 17:57:47 -0400 Subject: [PATCH 1/8] Update `read_nwb` --- src/probeinterface/io.py | 68 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/probeinterface/io.py b/src/probeinterface/io.py index 78f283b3..8a7024a4 100644 --- a/src/probeinterface/io.py +++ b/src/probeinterface/io.py @@ -10,7 +10,7 @@ """ from pathlib import Path -from typing import Union, Optional +from typing import Union, Optional, List import re import warnings import json @@ -1680,10 +1680,68 @@ def read_mearec(file: Union[str, Path]) -> Probe: return probe -def read_nwb(file): +def read_nwb(nwbfile: Union[Path, str])->List[Probe]: """ - Read probe position from an NWB file + Load ndx_probeinterface.Probe as + probeinterface.Probe objects from an NWB file + + Parameters + ---------- + nwbfile : Path or str + The path to nwbfile - """ + Returns + ------- + probe : Probe object - raise NotImplementedError + """ + try: + import ndx_probeinterface + import pynwb + except ImportError: + raise ImportError("Missing `ndx_probeinterface` or `pynwb`") + + with pynwb.NWBHDF5IO(nwbfile, mode='r', load_namespaces=True) as io: + nwbf = io.read() + ndx_probes = [] + for device in nwbf.devices: + if isinstance(device, ndx_probeinterface.Probe): + ndx_probes.append(device) + if not ndx_probes: + core_probe = _from_nwb_ElectrodeTable(nwbf.electrodes) + return core_probe + probes = [] + for ndx_probe in ndx_probes: + probes.append(ndx_probeinterface.to_probeinterface(ndx_probe)) + + return probes + +def _from_nwb_ElectrodeTable(nwbf_electrodes): + # infer dimension by + # 1. checking for columns with names 'rel_x', 'rel_y', 'rel_z' + # 2. checking how many of these columns have elements that are not all zero + rel_present = [rel for rel in ['rel_x', 'rel_y', 'rel_z'] if rel in nwbf_electrodes.columns] + true_rel_present = [] + for rel in rel_present: + if (nwbf_electrodes[rel][:]==0).all()==False: + true_rel_present.append(rel) + ndim = len(true_rel_present) + assert ndim>=1, "Insufficient position information to generate Probe object." + + # no way to read units when only ElectrodeTable is present; just assume microns + unit = "um" + + # create Probe + probeinterface_probe = Probe(ndim=ndim, si_units=unit) + + # infer positions + n_contacts = len(nwbf_electrodes) + positions = np.zeros((n_contacts,ndim)) + for i in range(ndim): + positions[:,i]= nwbf_electrodes[true_rel_present[i]][:] + + # set contacts + probeinterface_probe.set_contacts( + positions=positions, + ) + return probeinterface_probe \ No newline at end of file From 652ea35acb16dd83089e0d9743ce6d62f53f69a5 Mon Sep 17 00:00:00 2001 From: Kyu Hyun Lee Date: Fri, 28 Jul 2023 18:00:25 -0400 Subject: [PATCH 2/8] Update docstring --- src/probeinterface/io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/probeinterface/io.py b/src/probeinterface/io.py index 8a7024a4..b5d7d512 100644 --- a/src/probeinterface/io.py +++ b/src/probeinterface/io.py @@ -1692,8 +1692,8 @@ def read_nwb(nwbfile: Union[Path, str])->List[Probe]: Returns ------- - probe : Probe object - + probe : List[Probe] + List of Probe objects """ try: import ndx_probeinterface From c1d7f8a5d55a1760b085cf58bee642868f2021ba Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 28 Jul 2023 22:00:30 +0000 Subject: [PATCH 3/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/probeinterface/io.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/probeinterface/io.py b/src/probeinterface/io.py index b5d7d512..ba3ebfe1 100644 --- a/src/probeinterface/io.py +++ b/src/probeinterface/io.py @@ -1680,11 +1680,11 @@ def read_mearec(file: Union[str, Path]) -> Probe: return probe -def read_nwb(nwbfile: Union[Path, str])->List[Probe]: +def read_nwb(nwbfile: Union[Path, str]) -> List[Probe]: """ - Load ndx_probeinterface.Probe as + Load ndx_probeinterface.Probe as probeinterface.Probe objects from an NWB file - + Parameters ---------- nwbfile : Path or str @@ -1700,13 +1700,13 @@ def read_nwb(nwbfile: Union[Path, str])->List[Probe]: import pynwb except ImportError: raise ImportError("Missing `ndx_probeinterface` or `pynwb`") - - with pynwb.NWBHDF5IO(nwbfile, mode='r', load_namespaces=True) as io: + + with pynwb.NWBHDF5IO(nwbfile, mode="r", load_namespaces=True) as io: nwbf = io.read() ndx_probes = [] for device in nwbf.devices: if isinstance(device, ndx_probeinterface.Probe): - ndx_probes.append(device) + ndx_probes.append(device) if not ndx_probes: core_probe = _from_nwb_ElectrodeTable(nwbf.electrodes) return core_probe @@ -1716,32 +1716,33 @@ def read_nwb(nwbfile: Union[Path, str])->List[Probe]: return probes + def _from_nwb_ElectrodeTable(nwbf_electrodes): # infer dimension by # 1. checking for columns with names 'rel_x', 'rel_y', 'rel_z' # 2. checking how many of these columns have elements that are not all zero - rel_present = [rel for rel in ['rel_x', 'rel_y', 'rel_z'] if rel in nwbf_electrodes.columns] + rel_present = [rel for rel in ["rel_x", "rel_y", "rel_z"] if rel in nwbf_electrodes.columns] true_rel_present = [] for rel in rel_present: - if (nwbf_electrodes[rel][:]==0).all()==False: + if (nwbf_electrodes[rel][:] == 0).all() == False: true_rel_present.append(rel) ndim = len(true_rel_present) - assert ndim>=1, "Insufficient position information to generate Probe object." - + assert ndim >= 1, "Insufficient position information to generate Probe object." + # no way to read units when only ElectrodeTable is present; just assume microns unit = "um" - + # create Probe probeinterface_probe = Probe(ndim=ndim, si_units=unit) - + # infer positions n_contacts = len(nwbf_electrodes) - positions = np.zeros((n_contacts,ndim)) + positions = np.zeros((n_contacts, ndim)) for i in range(ndim): - positions[:,i]= nwbf_electrodes[true_rel_present[i]][:] - + positions[:, i] = nwbf_electrodes[true_rel_present[i]][:] + # set contacts probeinterface_probe.set_contacts( positions=positions, ) - return probeinterface_probe \ No newline at end of file + return probeinterface_probe From f5b4d1e3f962d16e04522e6f1c2e8c8f12a1ff4e Mon Sep 17 00:00:00 2001 From: Kyu Hyun Lee Date: Fri, 28 Jul 2023 18:02:26 -0400 Subject: [PATCH 4/8] Minor change --- src/probeinterface/io.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/probeinterface/io.py b/src/probeinterface/io.py index ba3ebfe1..2a8521f4 100644 --- a/src/probeinterface/io.py +++ b/src/probeinterface/io.py @@ -1709,7 +1709,7 @@ def read_nwb(nwbfile: Union[Path, str]) -> List[Probe]: ndx_probes.append(device) if not ndx_probes: core_probe = _from_nwb_ElectrodeTable(nwbf.electrodes) - return core_probe + return [core_probe] probes = [] for ndx_probe in ndx_probes: probes.append(ndx_probeinterface.to_probeinterface(ndx_probe)) From e35b715eae7352075bea0b2a04f481be4a79f0dd Mon Sep 17 00:00:00 2001 From: Kyu Hyun Lee Date: Fri, 28 Jul 2023 18:04:25 -0400 Subject: [PATCH 5/8] Add test_nwb.py --- tests/test_io/test_nwb.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/test_io/test_nwb.py diff --git a/tests/test_io/test_nwb.py b/tests/test_io/test_nwb.py new file mode 100644 index 00000000..f93e142e --- /dev/null +++ b/tests/test_io/test_nwb.py @@ -0,0 +1,15 @@ +from pathlib import Path +import numpy as np + +import pytest + +try: + import ndx_probeinterface + import pynwb +except ImportError: + raise ImportError("Missing `ndx_probeinterface` or `pynwb`") + +# data_path = Path(__file__).absolute().parent.parent / "data" / "nwb" + +def test_nwb(): + return NotImplemented \ No newline at end of file From 41134b95791ec8a2acc03b4495c47476b5bb8f7d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 28 Jul 2023 22:04:34 +0000 Subject: [PATCH 6/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_io/test_nwb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_io/test_nwb.py b/tests/test_io/test_nwb.py index f93e142e..17fdb8c8 100644 --- a/tests/test_io/test_nwb.py +++ b/tests/test_io/test_nwb.py @@ -12,4 +12,4 @@ # data_path = Path(__file__).absolute().parent.parent / "data" / "nwb" def test_nwb(): - return NotImplemented \ No newline at end of file + return NotImplemented From fddc0290f0c4980c6b17b544e00f9de8b7a39911 Mon Sep 17 00:00:00 2001 From: Kyu Hyun Lee Date: Sat, 29 Jul 2023 05:07:15 -0400 Subject: [PATCH 7/8] Fix `_from_nwb_ElectrodeTable` --- src/probeinterface/io.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/probeinterface/io.py b/src/probeinterface/io.py index 2a8521f4..15d01f91 100644 --- a/src/probeinterface/io.py +++ b/src/probeinterface/io.py @@ -1708,7 +1708,7 @@ def read_nwb(nwbfile: Union[Path, str]) -> List[Probe]: if isinstance(device, ndx_probeinterface.Probe): ndx_probes.append(device) if not ndx_probes: - core_probe = _from_nwb_ElectrodeTable(nwbf.electrodes) + core_probe = _from_nwb_ElectrodeTable(nwbf.electrodes[:]) return [core_probe] probes = [] for ndx_probe in ndx_probes: @@ -1718,6 +1718,20 @@ def read_nwb(nwbfile: Union[Path, str]) -> List[Probe]: def _from_nwb_ElectrodeTable(nwbf_electrodes): + """ + Load NWB core ElectrodeTable as probeinterface.Probe object + Warning: makes some assumptions + + Parameters + ---------- + nwbfile : Path or str + The path to nwbfile + + Returns + ------- + probeinterface_probe : Probe + """ + # infer dimension by # 1. checking for columns with names 'rel_x', 'rel_y', 'rel_z' # 2. checking how many of these columns have elements that are not all zero From 383ddf004d09100f1ef296a753472078a8bab5d8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 29 Jul 2023 09:07:23 +0000 Subject: [PATCH 8/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/probeinterface/io.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/probeinterface/io.py b/src/probeinterface/io.py index 15d01f91..b663584c 100644 --- a/src/probeinterface/io.py +++ b/src/probeinterface/io.py @@ -1726,12 +1726,12 @@ def _from_nwb_ElectrodeTable(nwbf_electrodes): ---------- nwbfile : Path or str The path to nwbfile - + Returns ------- probeinterface_probe : Probe """ - + # infer dimension by # 1. checking for columns with names 'rel_x', 'rel_y', 'rel_z' # 2. checking how many of these columns have elements that are not all zero