Created
June 17, 2023 12:29
-
-
Save rly/f33b9e9bb049ad5759fc631349bbe867 to your computer and use it in GitHub Desktop.
Test behavior of PyNWB/HDMF with an attribute spec that has a non-text or non-scalar default value.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"id": "a1d8169c-c17f-48b4-93df-3f0c1f8f24af", | |
"metadata": {}, | |
"source": [ | |
"## Question: Can you make an NWB/HDMF spec with an attribute that has a non-text or non-scalar default value?\n", | |
"Answer: Yes, but the default value will be read by PyNWB/HDMF as one of the default Python types str, int, float, and if it is non-scalar, it will be read as a list or list of lists. On write, a dtype precision can be imposed. As in normal PyNWB/HDMF, consistency of dtypes within a list or list of lists (as opposed to a numpy array) is not checked." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"id": "afad9520-af79-44c9-8975-81c597cf672e", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pynwb.spec import NWBGroupSpec, NWBAttributeSpec\n", | |
"from pynwb.spec import NWBNamespaceBuilder, export_spec" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"id": "d53d11d8-15c0-40b3-8002-5099aa9234eb", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"ns_builder = NWBNamespaceBuilder(\n", | |
" doc=\"test\",\n", | |
" name=\"ndx-spec-non-string-value\",\n", | |
" version=\"0.1.0\",\n", | |
" author=\"Ryan Ly\",\n", | |
" contact=\"rly@lbl.gov\",\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"id": "fc70c0fd-f2f4-4561-898a-f1f575f2ae82", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"test_spec1 = NWBGroupSpec(\n", | |
" neurodata_type_def='TestDefaultValueIntScalar',\n", | |
" neurodata_type_inc=\"NWBDataInterface\",\n", | |
" doc=\"test\",\n", | |
" attributes = [\n", | |
" NWBAttributeSpec(\n", | |
" name=\"test_attribute\",\n", | |
" dtype=\"int\",\n", | |
" doc=\"test\",\n", | |
" default_value=10,\n", | |
" ),\n", | |
" ],\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"id": "f2bbc4b0-da4e-4d1c-a5b4-b05a7ac5eabc", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"test_spec2 = NWBGroupSpec(\n", | |
" neurodata_type_def='TestDefaultValueInt2D',\n", | |
" neurodata_type_inc=\"NWBDataInterface\",\n", | |
" doc=\"test\",\n", | |
" attributes = [\n", | |
" NWBAttributeSpec(\n", | |
" name=\"test_attribute\",\n", | |
" dtype=\"int64\",\n", | |
" doc=\"test\",\n", | |
" shape=[None, None],\n", | |
" default_value=[[1, 2, 3], [4, 5, 6]],\n", | |
" # NOTE that lists allow mixing of dtypes\n", | |
" ),\n", | |
" ],\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"id": "62e532fb-d22e-4998-87e0-1c2a144c1129", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"test_spec3 = NWBGroupSpec(\n", | |
" neurodata_type_def='TestDefaultValueFloat2D',\n", | |
" neurodata_type_inc=\"NWBDataInterface\",\n", | |
" doc=\"test\",\n", | |
" attributes = [\n", | |
" NWBAttributeSpec(\n", | |
" name=\"test_attribute\",\n", | |
" dtype=\"float\",\n", | |
" doc=\"test\",\n", | |
" shape=[None, None],\n", | |
" default_value=[[1., 2., 3.], [4.1, 5.1, 6.1]],\n", | |
" ),\n", | |
" ],\n", | |
")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"id": "873d8a3e-3502-4ebc-bfe2-5f92958f33de", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"new_data_types = [test_spec1, test_spec2, test_spec3]" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"id": "7e94d8a3-526c-4f78-a0a4-ad5a7801ce07", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pathlib import Path\n", | |
"output_dir = \"ndx-spec-non-string-value\"\n", | |
"Path(output_dir).mkdir(exist_ok=True)\n", | |
"export_spec(ns_builder, new_data_types, output_dir)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"id": "87d5908b-680d-409d-9d30-9b9b8b6a21fc", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"from pynwb import get_class, load_namespaces\n", | |
"load_namespaces(\"ndx-spec-non-string-value/ndx-spec-non-string-value.namespace.yaml\");" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"id": "98f5cd33-c89c-434d-84e5-5363b21a6c96", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"TestDefaultValueIntScalar = get_class(\"TestDefaultValueIntScalar\", \"ndx-spec-non-string-value\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"id": "b646b5af-75ea-4ca8-9e17-96c499ed3e3d", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"obj abc.TestDefaultValueIntScalar at 0x4815574528\n", | |
"Fields:\n", | |
" test_attribute: 10" | |
] | |
}, | |
"execution_count": 10, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"TestDefaultValueIntScalar(name=\"obj\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"id": "7100f942-5746-4f3b-b51e-a7d97576132b", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"obj abc.TestDefaultValueIntScalar at 0x4815576688\n", | |
"Fields:\n", | |
" test_attribute: 20" | |
] | |
}, | |
"execution_count": 11, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"TestDefaultValueIntScalar(name=\"obj\", test_attribute=20)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"id": "baecc893-07e6-4878-bddc-4441b057d1fd", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# TestDefaultValueIntScalar(name=\"obj\", test_attribute=\"20\")\n", | |
"# generates error:\n", | |
"# TypeError: CustomClassGenerator.set_init.<locals>.__init__: incorrect type for 'test_attribute' (got 'str', expected 'int, int32 or int64')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 13, | |
"id": "29df90cc-7f7d-4628-9c44-f6502bf2e14f", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"TestDefaultValueInt2D = get_class(\"TestDefaultValueInt2D\", \"ndx-spec-non-string-value\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 14, | |
"id": "d5ebc1d3-386d-485d-90db-a81f01f4b6de", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"obj abc.TestDefaultValueInt2D at 0x4815575344\n", | |
"Fields:\n", | |
" test_attribute: [[1 2 3]\n", | |
" [4 5 6]]" | |
] | |
}, | |
"execution_count": 14, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"TestDefaultValueInt2D(name=\"obj\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 15, | |
"id": "fcf3ce5d-11e7-482c-ad55-76915139970f", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"[[1, 2, 3], [4, 5, 6]]" | |
] | |
}, | |
"execution_count": 15, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"TestDefaultValueInt2D(name=\"obj\").test_attribute" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 16, | |
"id": "12ed44c2-b2c8-4588-bec9-14cd67c57fb5", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"errors: []\n", | |
"<class 'numpy.ndarray'>\n", | |
"<class 'numpy.dtype[int64]'>\n", | |
"[[1 2 3]\n", | |
" [4 5 6]]\n" | |
] | |
} | |
], | |
"source": [ | |
"from pynwb import NWBFile, NWBHDF5IO, validate\n", | |
"import datetime\n", | |
"\n", | |
"nwbfile = NWBFile(\n", | |
" session_description=\"session_description\",\n", | |
" identifier=\"identifier\",\n", | |
" session_start_time=datetime.datetime.now(datetime.timezone.utc),\n", | |
")\n", | |
"\n", | |
"obj = TestDefaultValueInt2D(name=\"obj\")\n", | |
"nwbfile.add_acquisition(obj)\n", | |
"\n", | |
"filename = \"ndx-spec-non-string-value/test_out.nwb\"\n", | |
"\n", | |
"with NWBHDF5IO(filename, \"w\") as io:\n", | |
" io.write(nwbfile)\n", | |
"\n", | |
"with NWBHDF5IO(filename, \"r\") as io:\n", | |
" errors = validate(io)\n", | |
" print(\"errors:\", errors)\n", | |
" nwbfile = io.read()\n", | |
" print(type(nwbfile.acquisition[\"obj\"].test_attribute))\n", | |
" print(type(nwbfile.acquisition[\"obj\"].test_attribute.dtype))\n", | |
" print(nwbfile.acquisition[\"obj\"].test_attribute)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"id": "120988e2-41bd-4c3b-8384-c35efbc9640c", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/Users/rly/mambaforge/envs/test/lib/python3.10/site-packages/hdmf/build/objectmapper.py:260: DtypeConversionWarning: Spec 'TestDefaultValueInt2D/test_attribute': Value with data type float64 is being converted to data type int64 as specified.\n", | |
" warnings.warn(full_warning_msg, DtypeConversionWarning)\n" | |
] | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"errors: []\n", | |
"<class 'numpy.ndarray'>\n", | |
"<class 'numpy.dtype[int64]'>\n", | |
"[[1 2]\n", | |
" [3 4]]\n" | |
] | |
} | |
], | |
"source": [ | |
"from pynwb import NWBFile, NWBHDF5IO, validate\n", | |
"import datetime\n", | |
"\n", | |
"nwbfile = NWBFile(\n", | |
" session_description=\"session_description\",\n", | |
" identifier=\"identifier\",\n", | |
" session_start_time=datetime.datetime.now(datetime.timezone.utc),\n", | |
")\n", | |
"\n", | |
"obj = TestDefaultValueInt2D(name=\"obj\", test_attribute=[[1, 2.1], [3, 4]])\n", | |
"nwbfile.add_acquisition(obj)\n", | |
"\n", | |
"filename = \"ndx-spec-non-string-value/test_out.nwb\"\n", | |
"\n", | |
"with NWBHDF5IO(filename, \"w\") as io:\n", | |
" io.write(nwbfile)\n", | |
"\n", | |
"with NWBHDF5IO(filename, \"r\") as io:\n", | |
" errors = validate(io)\n", | |
" print(\"errors:\", errors)\n", | |
" nwbfile = io.read()\n", | |
" print(type(nwbfile.acquisition[\"obj\"].test_attribute))\n", | |
" print(type(nwbfile.acquisition[\"obj\"].test_attribute.dtype))\n", | |
" print(nwbfile.acquisition[\"obj\"].test_attribute)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"id": "ecbdc40a-9a5b-4781-aed6-1ba4f76e2bb6", | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"TestDefaultValueFloat2D = get_class(\"TestDefaultValueFloat2D\", \"ndx-spec-non-string-value\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 19, | |
"id": "1bad18ec-6d9d-4e39-bd7a-464a54c30006", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"obj abc.TestDefaultValueFloat2D at 0x4816245264\n", | |
"Fields:\n", | |
" test_attribute: [[1. 2. 3. ]\n", | |
" [4.1 5.1 6.1]]" | |
] | |
}, | |
"execution_count": 19, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"TestDefaultValueFloat2D(name=\"obj\")" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 20, | |
"id": "b4661159-6e41-4cbb-84a4-ff65393cfc24", | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"float" | |
] | |
}, | |
"execution_count": 20, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"type(TestDefaultValueFloat2D(name=\"obj\").test_attribute[0][0])" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"id": "cf3aefd9-a0a7-48a0-9b46-7fd28563df07", | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3 (ipykernel)", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.10.11" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 5 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment