From 7adf428aea91aa20456c7bf147a73ad4b9ed0de3 Mon Sep 17 00:00:00 2001 From: mavaylon1 Date: Mon, 20 May 2024 08:15:54 -0700 Subject: [PATCH] tutorial draft --- docs/gallery/general/plot_configurator.py | 189 +++++++++++----------- docs/gallery/general/plot_termset.py | 153 ------------------ src/pynwb/__init__.py | 37 +++-- 3 files changed, 118 insertions(+), 261 deletions(-) delete mode 100644 docs/gallery/general/plot_termset.py diff --git a/docs/gallery/general/plot_configurator.py b/docs/gallery/general/plot_configurator.py index fa96eeaf9..c326e6016 100644 --- a/docs/gallery/general/plot_configurator.py +++ b/docs/gallery/general/plot_configurator.py @@ -1,95 +1,94 @@ -# from datetime import datetime -# from uuid import uuid4 -# from hdmf.term_set import TermSetWrapper, TermSet -# -# import numpy as np -# from dateutil import tz -# -# from pynwb import NWBHDF5IO, NWBFile -# from pynwb.behavior import Position, SpatialSeries -# from pynwb.file import Subject -# from pynwb import unload_type_config, load_type_config -# -# load_type_config() -# session_start_time = datetime(2018, 4, 25, 2, 30, 3, tzinfo=tz.gettz("US/Pacific")) -# terms = TermSet(term_schema_path='/Users/mavaylon/Research/NWB/hdmf/docs/gallery/example_term_set.yaml') -# # -# nwbfile = NWBFile( -# session_description="Mouse exploring an open field", # required -# identifier=str(uuid4()), # required -# session_start_time=session_start_time, # required -# session_id="session_1234", # optional -# experimenter=[ -# "Ryan Ly", -# ], # optional -# lab="Bag End Laboratory", # optional -# institution="University of My Institution", # optional -# experiment_description="I went on an adventure to reclaim vast treasures.", # optional -# related_publications="DOI:10.1016/j.neuron.2016.12.011", # optional -# ) -# subject = Subject( -# subject_id="01", -# age="One shouldn't ask", -# description="A human.", -# species="Homo sapiens", -# sex="M", -# ) -# -# nwbfile.subject = subject -# -# device = nwbfile.create_device( -# name="array", description="the best array", manufacturer="Probe Company 9000" -# ) -# -# nwbfile.add_electrode_column(name="label", description="label of electrode") -# -# nshanks = 4 -# nchannels_per_shank = 3 -# electrode_counter = 0 -# -# for ishank in range(nshanks): -# # create an electrode group for this shank -# electrode_group = nwbfile.create_electrode_group( -# name="shank{}".format(ishank), -# description="electrode group for shank {}".format(ishank), -# device=device, -# location='Amygdala' -# ) -# # add electrodes to the electrode table -# for ielec in range(nchannels_per_shank): -# nwbfile.add_electrode( -# group=electrode_group, -# label="shank{}elec{}".format(ishank, ielec), -# location='Amygdala' -# ) -# electrode_counter += 1 -# -# breakpoint() -# # # nwbfile.subject = subject -# # # breakpoint() -# # unload_type_config() -# # load_type_config() -# # -# # nwbfile = NWBFile( -# # session_description="Mouse exploring an open field", # required -# # identifier=str(uuid4()), # required -# # session_start_time=session_start_time, # required -# # session_id="session_1234", # optional -# # experimenter=[ -# # "Ryan Ly", -# # ], # optional -# # lab="Bag End Laboratory", # optional -# # institution="University of My Institution", # optional -# # experiment_description="I went on an adventure to reclaim vast treasures.", # optional -# # related_publications="DOI:10.1016/j.neuron.2016.12.011", # optional -# # ) -# # -# # -# # subject = Subject( -# # subject_id="001", -# # age="P90D", -# # description="mouse 5", -# # species="Mus musculus", -# # sex="M", -# # ) -# # breakpoint() +""" +TypeConfigurator +======= + +This is a user guide for how to take advantage of the +:py:class:`~hdmf.term_set.TypeConfigurator` class by creating configuration files in +order to more easily validate terms within datasets or attributes. + +Introduction +------------- +Users do not directly interact with the :py:class:`~hdmf.term_set.TypeConfigurator` class. +Instead, users wil create a configuration YAML file that outlines the fields from which structures +they want to be targeted. After creating the configuration file, users will need to load the +configuration with the method. With the configuration loaded, every instance of the neurodata +types defined in the configuration file will have the respective fields wrapped with a +. This automatic wrapping is what provides the term validation for the the field value. +If a user wants to have greater control on which instances have validated fields, the user cannot use the +configurator, bur rather proceed with manually wrapping with a . + +To unload a configuration, simply call . We also provide a helper method to see the configuration +that has been loaded: + + +How to make a Configuration File +-------------------------------- +Before taking advantage of the all the wonders that comes with using a configuration file, +the user needs to create one following some simple guidelines. To follow along with an example, +please refer to <>. The configuration files is built on the foundation of the YAML syntax. The +user will construct a series of nested dictioanries to encompass all the necessary information. + +1. The user needs to define all the relevant namespaces. Recall that each neurodata type exists within + a namespace, whether that is the core namespace in PyNWB or a namespace in an extension. As namespaces grow, + we also require a version to be recorded in the configuration file to ensure proper functionality. +2. Within a namespace dictionary, the user will have a list of data types the want to use. +3. Each data type will have a list of fields associated with a . The user can use the same or + unique TermSet instances for each field. +""" +try: + import linkml_runtime # noqa: F401 +except ImportError as e: + raise ImportError("Please install linkml-runtime to run this example: pip install linkml-runtime") from e +from hdmf.term_set import TermSet, TermSetWrapper + +# How to use a Configuration file +# ------------------------------- +# As mentioned prior, the first step after creating a configuration file is +# to load the file. +# It is important to remember that with the configuration loaded, the fields +# are wrapped automatically, meaning the user should proceed with creating +# the instances normally, i.e., without wrapping directly. In this example, +# we load the the NWB curated configuration file that associates a +# for the species field in Subject. + +load_type_config() + +session_start_time = datetime(2018, 4, 25, hour=2, minute=30, second=3, tzinfo=tz.gettz("US/Pacific")) + +nwbfile = NWBFile( + session_description="Mouse exploring an open field", # required + identifier=str(uuid4()), # required + session_start_time=session_start_time, # required + session_id="session_1234", # optional + experimenter=[ + "Baggins, Bilbo", + ], # optional + lab="Bag End Laboratory", # optional + institution="University of My Institution", # optional + experiment_description="I went on an adventure to reclaim vast treasures.", # optional + related_publications="DOI:10.1016/j.neuron.2016.12.011", # optional +) + +subject = Subject( + subject_id="001", + age="P90D", + description="mouse 5", + species="Mus musculus", + sex="M", +) + +nwbfile.subject = subject +subject + +#################################### +# How to see the Configuration file +# --------------------------------- +# Users can retrieve the loaded configuration. +config = get_loaded_type_config() + +###################################### +# How to unload the Configuration file +# ------------------------------------ +# In order to toggle off the automatic validation, the user simple needs to unload +# the configuration. +unload_type_config() diff --git a/docs/gallery/general/plot_termset.py b/docs/gallery/general/plot_termset.py deleted file mode 100644 index 7fe883047..000000000 --- a/docs/gallery/general/plot_termset.py +++ /dev/null @@ -1,153 +0,0 @@ -# from hdmf.term_set import TermSet, TermSetWrapper -# from pynwb.resources import HERD -# from pynwb import NWBHDF5IO, NWBFile -# from glob import glob -# from tqdm import tqdm -# from dandi.dandiapi import DandiAPIClient -# import fsspec -# from fsspec.implementations.cached import CachingFileSystem -# import h5py -# import pynwb -# from pynwb.file import Subject -# -# from hdmf.common import VectorData -# -# from datetime import datetime -# from dateutil import tz -# import yaml -# -# from datetime import datetime -# from uuid import uuid4 -# -# import numpy as np -# from dateutil.tz import tzlocal -# -# from pynwb import NWBHDF5IO, NWBFile, get_type_map -# from pynwb.file import ElectrodeTable -# from pynwb.ecephys import LFP, ElectricalSeries -# -# from pynwb import unload_termset_config, load_termset_config, get_loaded_config -# -# experimenter_termset = ... -# location_termset = ... -# species_termset = ... -# # et = ElectrodeTable() -# # breakpoint() -# # # tm=get_type_map() -# # cc=get_loaded_config() -# # breakpoint() -# # unload_termset_config() -# # cc2=get_loaded_config() -# # -# load_termset_config() -# cc2=get_loaded_config() -# breakpoint() -# load_termset_config('/Users/mavaylon/Research/NWB/hdmf2/hdmf/tests/unit/test_extension_config.yaml') -# cc3=get_loaded_config() -# -# breakpoint() -# -# tm=get_type_map() -# location_termset =... -# -# -# # Example with Electrophys location, with species, with orcid -# -# nwbfile = NWBFile( -# session_description="my first synthetic recording", -# identifier=str(uuid4()), -# session_start_time=datetime.now(tzlocal()), -# experimenter=[ -# "Ryan Ly", -# ], -# lab="Bag End Laboratory", -# institution="University of Middle Earth at the Shire", -# experiment_description="I went on an adventure to reclaim vast treasures.", -# session_id="LONELYMTN001", -# ) -# -# device = nwbfile.create_device( -# name="array", description="the best array", manufacturer="Probe Company 9000" -# ) -# -# nwbfile.add_electrode_column(name="label", description="label of electrode") -# -# nshanks = 4 -# nchannels_per_shank = 3 -# electrode_counter = 0 -# -# for ishank in range(nshanks): -# # create an electrode group for this shank -# electrode_group = nwbfile.create_electrode_group( -# name="shank{}".format(ishank), -# description="electrode group for shank {}".format(ishank), -# device=device, -# location='Amygdala', -# ) -# # add electrodes to the electrode table -# for ielec in range(nchannels_per_shank): -# nwbfile.add_electrode( -# group=electrode_group, -# label="shank{}elec{}".format(ishank, ielec), -# location='Amygdala', -# ) -# electrode_counter += 1 -# -# nwbfile.electrodes.to_dataframe() -# breakpoint() -# -# # Example with Electrophys location, with species, with orcid -# -# # nwbfile = NWBFile( -# # session_description="my first synthetic recording", -# # identifier=str(uuid4()), -# # session_start_time=datetime.now(tzlocal()), -# # experimenter=TermSetWrapper(value=['Oliver RĂ¼bel', 'Ryan Ly'], termset=experimenter_termset), -# # lab="Bag End Laboratory", -# # institution="University of Middle Earth at the Shire", -# # experiment_description="I went on an adventure to reclaim vast treasures.", -# # session_id="LONELYMTN001", -# # ) -# # -# # subject = Subject( -# # subject_id="01", -# # age="One shouldn't ask", -# # description="A human.", -# # species=TermSetWrapper(value="Homo sapiens", termset=species_termset), -# # sex="M", -# # ) -# # -# # nwbfile.subject = subject -# # device = nwbfile.create_device( -# # name="array", description="the best array", manufacturer="Probe Company 9000" -# # ) -# # -# # nwbfile.add_electrode_column(name="label", description="label of electrode") -# # -# # nshanks = 4 -# # nchannels_per_shank = 3 -# # electrode_counter = 0 -# # -# # for ishank in range(nshanks): -# # # create an electrode group for this shank -# # electrode_group = nwbfile.create_electrode_group( -# # name="shank{}".format(ishank), -# # description="electrode group for shank {}".format(ishank), -# # device=device, -# # location=TermSetWrapper(value='Amygdala', termset=location_termset), -# # ) -# # # add electrodes to the electrode table -# # for ielec in range(nchannels_per_shank): -# # nwbfile.add_electrode( -# # group=electrode_group, -# # label="shank{}elec{}".format(ishank, ielec), -# # location='Amygdala' -# # ) -# # electrode_counter += 1 -# # breakpoint() -# # with NWBHDF5IO("basics_tutorial.nwb",herd_path='./HERD.zip', mode= "w") as io: -# # io.write(nwbfile) -# # -# # # Automatically writes HERD using TermSetWrapper as the flag. -# # with NWBHDF5IO("basics_tutorial.nwb",herd_path='HERD.zip', mode="r") as io: -# # read_nwbfile = io.read() diff --git a/src/pynwb/__init__.py b/src/pynwb/__init__.py index 4c957a2be..1114407da 100644 --- a/src/pynwb/__init__.py +++ b/src/pynwb/__init__.py @@ -12,6 +12,10 @@ from hdmf.backends.hdf5 import HDF5IO as _HDF5IO from hdmf.build import BuildManager, TypeMap import hdmf.common +from hdmf.common import load_type_config as hdmf_load_type_config +from hdmf.common import get_loaded_type_config as hdmf_get_loaded_type_config +from hdmf.common import unload_type_config as hdmf_unload_type_config + CORE_NAMESPACE = 'core' @@ -22,26 +26,33 @@ CUR_DIR = os.path.dirname(os.path.realpath(__file__)) path_to_config = os.path.join(CUR_DIR, 'config/nwb_config.yaml') -def get_loaded_type_config(): - if __TYPE_MAP.type_config.config is None: - msg = "No configuration is loaded." - raise ValueError(msg) - else: - return __TYPE_MAP.type_config.config - -def load_type_config(config_path: str = None): +@docval({'name': 'config_path', 'type': str, 'doc': 'Path to the configuration file.', + 'default': None}, + {'name': 'type_map', 'type': TypeMap, 'doc': 'The TypeMap.', 'default': None}, + is_method=False) +def load_type_config(**kwargs): """ This method will either load the default config or the config provided by the path. """ - if config_path is None: - config_path = path_to_config - __TYPE_MAP.type_config.load_type_config(config_path) + config_path = kwargs['config_path'] or path_to_config + type_map = kwargs['type_map'] or get_type_map() -def unload_type_config(): + hdmf_load_type_config(config_path=config_path, type_map=get_type_map()) + +@docval({'name': 'type_map', 'type': TypeMap, 'doc': 'The TypeMap.', 'default': None}, + is_method=False) +def get_loaded_type_config(**kwargs): + type_map = kwargs['type_map'] or get_type_map() + return hdmf_get_loaded_type_config(type_map=type_map) + +@docval({'name': 'type_map', 'type': TypeMap, 'doc': 'The TypeMap.', 'default': None}, + is_method=False) +def unload_type_config(**kwargs): """ Remove validation. """ - return __TYPE_MAP.type_config.unload_type_config() + type_map = kwargs['type_map'] or get_type_map() + hdmf_unload_type_config(type_map=type_map) def __get_resources(): try: