diff --git a/CHANGELOG.md b/CHANGELOG.md index 32ee07a..681b714 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) convention. +## [0.1.0b1] - 2022-01-28 +### Added ++ Added functions to generate dictionaries for NWB export. + + ## [0.1.0b0] - 2021-05-07 ### Added + First beta release @@ -12,6 +17,6 @@ Observes [Semantic Versioning](https://semver.org/spec/v2.0.0.html) standard and + Added GitHub Action release process + Added `lab` schema - +[0.1.0b1]: https://github.com/datajoint/element-lab/compare/0.1.0b0...0.1.0b1 [0.1.0b0]: https://github.com/datajoint/element-lab/compare/0.1.0a1...0.1.0b0 [0.1.0a1]: https://github.com/datajoint/element-lab/releases/tag/0.1.0a1 diff --git a/Dockerfile b/Dockerfile index 4fbcfc9..c144a40 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,9 +5,9 @@ ARG PKG_NAME ARG PKG_VERSION FROM datajoint/${IMAGE}:py${PY_VER}-${DISTRO} -COPY --chown=dja:anaconda ./requirements.txt ./setup.py \ +COPY --chown=anaconda:anaconda ./requirements.txt ./setup.py \ /main/ -COPY --chown=dja:anaconda ./${PKG_NAME} /main/${PKG_NAME} +COPY --chown=anaconda:anaconda ./${PKG_NAME} /main/${PKG_NAME} RUN \ cd /main && \ pip install . && \ diff --git a/element_lab/__init__.py b/element_lab/__init__.py index 6334b3e..e69de29 100644 --- a/element_lab/__init__.py +++ b/element_lab/__init__.py @@ -1,4 +0,0 @@ -__author__ = "DataJoint NEURO" -__date__ = "December 15, 2020" -__version__ = "0.0.1" -__all__ = ['__author__', '__version__', '__date__'] \ No newline at end of file diff --git a/element_lab/export/__init__.py b/element_lab/export/__init__.py new file mode 100644 index 0000000..a97b5ef --- /dev/null +++ b/element_lab/export/__init__.py @@ -0,0 +1 @@ +from .nwb import elementlab_nwb_dict \ No newline at end of file diff --git a/element_lab/export/nwb.py b/element_lab/export/nwb.py new file mode 100644 index 0000000..8aac6ed --- /dev/null +++ b/element_lab/export/nwb.py @@ -0,0 +1,84 @@ +from element_lab import lab + + +def lab_to_nwb_dict(lab_key): + """ + Generate a dictionary containing all relevant lab and institution info + :param lab_key: Key specifying one entry in element_lab.lab.Lab + :return: dictionary with NWB parameters + """ + lab_info = (lab.Lab & lab_key).fetch1() + return dict( + institution=lab_info.get('institution'), + lab=lab_info.get('lab_name'), + ) + + +def project_to_nwb_dict(project_key): + """ + Generate a dictionary object containing relevant project information + (e.g., experimental description, related publications, etc.). + :param project_key: Key specifying one entry in element_lab.lab.Project + :return: dictionary with NWB parameters + """ + project_info = (lab.Project & project_key).fetch1() + return dict( + experiment_description=project_info.get('project_description'), + keywords=(lab.ProjectKeywords() & project_key + ).fetch('keyword').tolist() or None, + related_publications=(lab.ProjectPublication() & project_key + ).fetch('publication').tolist() or None + ) + + +def protocol_to_nwb_dict(protocol_key): + """ + Generate a dictionary object containing all protocol title and notes. + :param protocol_key: Key specifying one entry in element_lab.lab.Protocol + :return: dictionary with NWB parameters + """ + protocol_info = (lab.Protocol & protocol_key).fetch1() + return dict( + protocol=protocol_info.get('protocol'), + notes=protocol_info.get('protocol_description') + ) + + +def element_lab_to_nwb_dict(lab_key=None, project_key=None, protocol_key=None): + """ + Generate a dictionary object containing all relevant lab information used + when generating an NWB file at the session level. + All parameters optional, but should only specify one of respective type + Use: mynwbfile = pynwb.NWBFile(identifier="your identifier", + session_description="your description", + session_start_time=session_datetime, + **element_lab_to_nwb_dict( + lab_key=key1, + project_key=key2, + protocol_key=key3)) + + :param lab_key: Key specifying one entry in element_lab.lab.Lab + :param project_key: Key specifying one entry in element_lab.lab.Project + :param protocol_key: Key specifying one entry in element_lab.lab.Protocol + :return: dictionary with NWB parameters + """ + # Validate input + assert any([lab_key, project_key, protocol_key]), 'Must specify one key.' + assert lab_key is None or len(lab.Lab & lab_key) == 1, \ + 'Multiple labs error! The lab_key should specify only one lab.' + assert project_key is None or len(lab.Project & project_key) == 1, \ + 'Multiple projects error! The project_key should specify only one '\ + 'project.' + assert protocol_key is None or len(lab.Protocol & protocol_key) == 1, \ + 'Multiple protocols error! The protocol_key should specify only one '\ + 'protocol.' + + element_info = dict() + if lab_key: + element_info.update(lab_to_nwb_dict(lab_key)) + if project_key: + element_info.update(project_to_nwb_dict(project_key)) + if protocol_key: + element_info.update(protocol_to_nwb_dict(protocol_key)) + + return element_info diff --git a/element_lab/lab.py b/element_lab/lab.py index c71bf12..10c9ef5 100644 --- a/element_lab/lab.py +++ b/element_lab/lab.py @@ -6,22 +6,26 @@ def activate(schema_name, create_schema=True, create_tables=True): """ activate(schema_name, create_schema=True, create_tables=True) - :param schema_name: schema name on the database server to activate the `lab` element - :param create_schema: when True (default), create schema in the database if it does not yet exist. - :param create_tables: when True (default), create tables in the database if they do not yet exist. + :param schema_name: schema name on the database server to activate the + `lab` element + :param create_schema: when True (default), create schema in the + database if it does not yet exist. + :param create_tables: when True (default), create tables in the + database if they do not yet exist. """ - schema.activate(schema_name, create_schema=create_schema, create_tables=create_tables) + schema.activate(schema_name, create_schema=create_schema, + create_tables=create_tables) @schema class Lab(dj.Lookup): definition = """ - lab : varchar(24) # Abbreviated lab name + lab : varchar(24) # Abbreviated lab name --- lab_name : varchar(255) # full lab name institution : varchar(255) address : varchar(255) - time_zone : varchar(64) + time_zone : varchar(64) # 'UTC±X' format for NWB export """ @@ -77,7 +81,7 @@ class Protocol(dj.Lookup): protocol : varchar(16) --- -> ProtocolType - protocol_description='' : varchar(255) + protocol_description='' : varchar(255) """ @@ -86,7 +90,33 @@ class Project(dj.Lookup): definition = """ project : varchar(32) --- - project_description='' : varchar(1024) + project_description='' : varchar(1024) + """ + + +class ProjectKeywords(dj.Manual): + definition = """ + # Project keywords, exported dataset meta info + -> Project + keyword: varchar(32) + """ + + +class ProjectPublication(dj.Manual): + definition = """ + # Project's resulting publications + -> Project + publication: varchar(256) + """ + + +class ProjectSourceCode(dj.Manual): + definition = """ + # URL to source code for replication + -> Project + repository_url : varchar(256) + --- + repository_name='' : varchar(32) """ @@ -102,9 +132,9 @@ class ProjectUser(dj.Manual): class Source(dj.Lookup): definition = """ # source or supplier of animals - source : varchar(32) # abbreviated source name + source : varchar(32) # abbreviated source name --- - source_name : varchar(255) - contact_details='' : varchar(255) - source_description='' : varchar(255) + source_name : varchar(255) + contact_details='' : varchar(255) + source_description='' : varchar(255) """ diff --git a/element_lab/version.py b/element_lab/version.py index 5d6e909..c36d94e 100644 --- a/element_lab/version.py +++ b/element_lab/version.py @@ -1,2 +1,2 @@ """Package metadata.""" -__version__ = '0.1.0b0' \ No newline at end of file +__version__ = '0.1.0b1' diff --git a/requirements.txt b/requirements.txt index fc7a8e6..91e70c6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ datajoint>=0.13.0 +pynwb==1.4.0