diff --git a/src/pynwb/ndx_extracellular_channels/io.py b/src/pynwb/ndx_extracellular_channels/io.py index f9833ed..0044ee6 100644 --- a/src/pynwb/ndx_extracellular_channels/io.py +++ b/src/pynwb/ndx_extracellular_channels/io.py @@ -17,8 +17,8 @@ def from_probeinterface( - probe_or_probegroup: Union[probeinterface.Probe, probeinterface.ProbeGroup], - name: Union[str, list] = None, + probe_or_probegroup: Union[probeinterface.Probe, probeinterface.ProbeGroup], + name: Union[str, list] = None, ) -> List[ndx_extracellular_channels.Probe]: """ Construct ndx-extracellular-channels Probe objects from a probeinterface.Probe or probeinterface.ProbeGroup. @@ -43,8 +43,9 @@ def from_probeinterface( "To use the probeinterface conversion functions, install probeinterface: pip install probeinterface" ) - assert isinstance(probe_or_probegroup, (probeinterface.Probe, probeinterface.ProbeGroup)), \ - f"The input must be a Probe or ProbeGroup, not {type(probe_or_probegroup)}." + assert isinstance( + probe_or_probegroup, (probeinterface.Probe, probeinterface.ProbeGroup) + ), f"The input must be a Probe or ProbeGroup, not {type(probe_or_probegroup)}." if isinstance(probe_or_probegroup, probeinterface.Probe): probes = [probe_or_probegroup] else: @@ -155,8 +156,7 @@ def to_probeinterface(ndx_probe: ndx_extracellular_channels.Probe) -> probeinter def _single_probe_to_ndx_probe( - probe: probeinterface.Probe, - name: Union[str, None] = None + probe: probeinterface.Probe, name: Union[str, None] = None ) -> ndx_extracellular_channels.Probe: contacts_arr = probe.to_numpy() @@ -219,4 +219,4 @@ def _single_probe_to_ndx_probe( identifier=probe.serial_number, ) - return probe \ No newline at end of file + return probe diff --git a/src/pynwb/tests/test_classes.py b/src/pynwb/tests/test_classes.py index 19212ac..b44792b 100644 --- a/src/pynwb/tests/test_classes.py +++ b/src/pynwb/tests/test_classes.py @@ -474,8 +474,8 @@ def test_constructor_add_row(self): name="Neuropixels1ChannelsTable", # test custom name description="Test channels table", reference_mode="Referenced to channel 2.", - position_reference = "(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface.", - position_confirmation_method = "Histology", + position_reference="(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface.", + position_confirmation_method="Histology", probe=probe, probe_insertion=pi, target_tables={ @@ -555,8 +555,8 @@ def addContainer(self): name="Neuropixels1ChannelsTable", # test custom name description="Test channels table", reference_mode="Referenced to channel 2.", - position_reference = "(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface.", - position_confirmation_method = "Histology", + position_reference="(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface.", + position_confirmation_method="Histology", probe=probe, probe_insertion=pi, target_tables={ diff --git a/src/pynwb/tests/test_example_usage_all.py b/src/pynwb/tests/test_example_usage_all.py index c34ffdc..38fea35 100644 --- a/src/pynwb/tests/test_example_usage_all.py +++ b/src/pynwb/tests/test_example_usage_all.py @@ -85,8 +85,8 @@ name="Neuropixels1ChannelsTable", # test custom name description="Test channels table", reference_mode="Referenced to channel 2.", - position_reference = "(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface.", - position_confirmation_method = "Histology", + position_reference="(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface.", + position_confirmation_method="Histology", probe=probe, probe_insertion=pi, target_tables={ diff --git a/src/pynwb/tests/test_example_usage_probeinterface.py b/src/pynwb/tests/test_example_usage_probeinterface.py index d7e910f..d816ee7 100644 --- a/src/pynwb/tests/test_example_usage_probeinterface.py +++ b/src/pynwb/tests/test_example_usage_probeinterface.py @@ -5,6 +5,7 @@ import pynwb import uuid + def test_from_probeinterface(): # following the probeinterface tutorial, create a few probes @@ -27,7 +28,7 @@ def test_from_probeinterface(): ) probe0.set_contacts(positions=positions, shapes="circle", shape_params={"radius": 5}) - polygon = [(-20., -30.), (20., -110.), (60., -30.), (60., 190.), (-20., 190.)] + polygon = [(-20.0, -30.0), (20.0, -110.0), (60.0, -30.0), (60.0, 190.0), (-20.0, 190.0)] probe0.set_planar_contour(polygon) probe1 = probeinterface.generate_dummy_probe(elec_shapes="circle") @@ -81,8 +82,14 @@ def test_from_probeinterface(): with pynwb.NWBHDF5IO("test_probeinterface.nwb", "r", load_namespaces=True) as io: nwbfile = io.read() assert set(nwbfile.devices.keys()) == { - "probe0", "probe1", "probe2", "probe3", "a1x32-edge-5mm-20-177_H32", "Dummy Neuropixels 1.0", - "Dummy Neuropixels 2.0", "Dummy Neuropixels 3.0" + "probe0", + "probe1", + "probe2", + "probe3", + "a1x32-edge-5mm-20-177_H32", + "Dummy Neuropixels 1.0", + "Dummy Neuropixels 2.0", + "Dummy Neuropixels 3.0", } for device in nwbfile.devices.values(): assert isinstance(device, (ndx_extracellular_channels.ProbeModel, ndx_extracellular_channels.Probe)) @@ -103,7 +110,7 @@ def test_from_probeinterface(): assert np.all(nwbfile.devices["probe0"].probe_model.planar_contour_in_um == polygon) assert np.allclose(nwbfile.devices["probe0"].probe_model.contacts_table.relative_position_in_mm, positions) assert np.all(nwbfile.devices["probe0"].probe_model.contacts_table["shape"].data[:] == "circle") - assert np.all(nwbfile.devices["probe0"].probe_model.contacts_table["radius_in_um"].data[:] == 5.) + assert np.all(nwbfile.devices["probe0"].probe_model.contacts_table["radius_in_um"].data[:] == 5.0) assert nwbfile.devices["probe1"].name == "probe1" assert nwbfile.devices["probe1"].identifier == "1000" @@ -111,9 +118,13 @@ def test_from_probeinterface(): assert nwbfile.devices["probe1"].probe_model.manufacturer == "IMEC" assert nwbfile.devices["probe1"].probe_model.ndim == 2 assert np.allclose(nwbfile.devices["probe1"].probe_model.planar_contour_in_um, probe1.probe_planar_contour) - assert np.allclose(nwbfile.devices["probe1"].probe_model.contacts_table.relative_position_in_mm, probe1.contact_positions) + assert np.allclose( + nwbfile.devices["probe1"].probe_model.contacts_table.relative_position_in_mm, probe1.contact_positions + ) assert np.all(nwbfile.devices["probe1"].probe_model.contacts_table["shape"].data[:] == "circle") - assert np.all(nwbfile.devices["probe1"].probe_model.contacts_table["radius_in_um"].data[:] == probe1.to_numpy()["radius"]) + assert np.all( + nwbfile.devices["probe1"].probe_model.contacts_table["radius_in_um"].data[:] == probe1.to_numpy()["radius"] + ) assert nwbfile.devices["probe2"].name == "probe2" assert nwbfile.devices["probe2"].identifier == "1001" @@ -121,9 +132,13 @@ def test_from_probeinterface(): assert nwbfile.devices["probe2"].probe_model.manufacturer == "IMEC" assert nwbfile.devices["probe2"].probe_model.ndim == 2 assert np.allclose(nwbfile.devices["probe2"].probe_model.planar_contour_in_um, probe2.probe_planar_contour) - assert np.allclose(nwbfile.devices["probe2"].probe_model.contacts_table.relative_position_in_mm, probe2.contact_positions) + assert np.allclose( + nwbfile.devices["probe2"].probe_model.contacts_table.relative_position_in_mm, probe2.contact_positions + ) assert np.all(nwbfile.devices["probe2"].probe_model.contacts_table["shape"].data[:] == "square") - assert np.all(nwbfile.devices["probe2"].probe_model.contacts_table["width_in_um"].data[:] == probe2.to_numpy()["width"]) + assert np.all( + nwbfile.devices["probe2"].probe_model.contacts_table["width_in_um"].data[:] == probe2.to_numpy()["width"] + ) assert nwbfile.devices["probe3"].name == "probe3" assert nwbfile.devices["probe3"].identifier == "1002" @@ -131,9 +146,13 @@ def test_from_probeinterface(): assert nwbfile.devices["probe3"].probe_model.manufacturer == "IMEC" assert nwbfile.devices["probe3"].probe_model.ndim == 2 assert np.allclose(nwbfile.devices["probe3"].probe_model.planar_contour_in_um, probe3.probe_planar_contour) - assert np.allclose(nwbfile.devices["probe3"].probe_model.contacts_table.relative_position_in_mm, probe3.contact_positions) + assert np.allclose( + nwbfile.devices["probe3"].probe_model.contacts_table.relative_position_in_mm, probe3.contact_positions + ) assert np.all(nwbfile.devices["probe3"].probe_model.contacts_table["shape"].data[:] == "circle") - assert np.all(nwbfile.devices["probe3"].probe_model.contacts_table["radius_in_um"].data[:] == probe3.to_numpy()["radius"]) + assert np.all( + nwbfile.devices["probe3"].probe_model.contacts_table["radius_in_um"].data[:] == probe3.to_numpy()["radius"] + ) # for device in nwbfile.devices.values(): # print("-------------------") @@ -148,4 +167,4 @@ def test_from_probeinterface(): # pi_probe = ndx_extracellular_channels.to_probeinterface(device) # print(pi_probe) - # TODO add more tests for other probeinterface IO functions \ No newline at end of file + # TODO add more tests for other probeinterface IO functions diff --git a/src/spec/create_extension_spec.py b/src/spec/create_extension_spec.py index e482ce0..aecffaf 100644 --- a/src/spec/create_extension_spec.py +++ b/src/spec/create_extension_spec.py @@ -78,13 +78,15 @@ def main(): # NOTE: cannot end this name with "_index" because it conflicts with ragged arrays name="device_channel", neurodata_type_inc="VectorData", - doc=("Index of the channel connected to the contact on the device. " - "Probes can have a complex contact indexing system due to the probe layout. " - "When they are plugged into a recording device like an Open Ephys with an Intan headstage, " - "the channel order can be mixed again. So the physical contact channel index " - "is rarely the channel index on the device. See the probeinterface tutorial on automatic " - "wiring for an example: " - "https://probeinterface.readthedocs.io/en/main/examples/ex_11_automatic_wiring.html#sphx-glr-examples-ex-11-automatic-wiring-py"), + doc=( + "Index of the channel connected to the contact on the device. " + "Probes can have a complex contact indexing system due to the probe layout. " + "When they are plugged into a recording device like an Open Ephys with an Intan headstage, " + "the channel order can be mixed again. So the physical contact channel index " + "is rarely the channel index on the device. See the probeinterface tutorial on automatic " + "wiring for an example: " + "https://probeinterface.readthedocs.io/en/main/examples/ex_11_automatic_wiring.html#sphx-glr-examples-ex-11-automatic-wiring-py" + ), dtype="int", quantity="?", ), @@ -162,8 +164,10 @@ def main(): probe_model = NWBGroupSpec( neurodata_type_def="ProbeModel", neurodata_type_inc="Device", - doc=("Neural probe object, compatible with the ProbeInterface specification. The name of the object should " - 'be the model name of the probe, e.g., "Neuropixels 1.0".'), + doc=( + "Neural probe object, compatible with the ProbeInterface specification. The name of the object should " + 'be the model name of the probe, e.g., "Neuropixels 1.0".' + ), groups=[ NWBGroupSpec( name="contacts_table", @@ -184,11 +188,13 @@ def main(): ), NWBAttributeSpec( name="planar_contour_in_um", # TODO should this just be "contour"? - doc=("The coordinates of the nodes of the polygon that describe the shape (contour) of the probe, " - "in micrometers. The first and last points are connected to close the polygon. " - "e.g., [(-20., -30.), (20., -110.), (60., -30.), (60., 190.), (-20., 190.)]." - "See 'probe_planar_contour' in " - "https://probeinterface.readthedocs.io/en/main/format_spec.html for more details."), + doc=( + "The coordinates of the nodes of the polygon that describe the shape (contour) of the probe, " + "in micrometers. The first and last points are connected to close the polygon. " + "e.g., [(-20., -30.), (20., -110.), (60., -30.), (60., 190.), (-20., 190.)]." + "See 'probe_planar_contour' in " + "https://probeinterface.readthedocs.io/en/main/format_spec.html for more details." + ), dtype="float", dims=[["num_points", "x, y"], ["num_points", "x, y, z"]], shape=[[None, 2], [None, 3]], @@ -422,22 +428,28 @@ def main(): attributes=[ NWBAttributeSpec( name="position_reference", - doc=("Location of the origin (0, 0, 0) for `{X}_position_{Y}_in_mm` coordinates, e.g., " - '"(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface".'), + doc=( + "Location of the origin (0, 0, 0) for `{X}_position_{Y}_in_mm` coordinates, e.g., " + '"(AP, ML, DV) = (0, 0, 0) corresponds to bregma at the cortical surface".' + ), dtype="text", required=False, ), NWBAttributeSpec( name="reference_mode", - doc=('The reference mode used for the recording; e.g., "external wire in CSF", ' - 'common reference", "skull screw over frontal cortex".'), + doc=( + 'The reference mode used for the recording; e.g., "external wire in CSF", ' + 'common reference", "skull screw over frontal cortex".' + ), dtype="text", required=False, ), NWBAttributeSpec( name="position_confirmation_method", - doc=("Description of the method used to confirm the position of the contacts or brain area, " - 'e.g., "histology", "MRI".'), + doc=( + "Description of the method used to confirm the position of the contacts or brain area, " + 'e.g., "histology", "MRI".' + ), dtype="text", required=False, ),