|
| 1 | +""" |
| 2 | +Portions of code adapted from DeepLabCut/DLC2NWB |
| 3 | +MIT License Copyright (c) 2022 Alexander Mathis |
| 4 | +DataJoint export methods for DeepLabCut 2.x |
| 5 | +""" |
| 6 | +import logging |
| 7 | +import warnings |
| 8 | +from pathlib import Path |
| 9 | +from collections import abc |
| 10 | +from pynwb import NWBHDF5IO |
| 11 | +from hdmf.build.warnings import DtypeConversionWarning |
| 12 | +from .. import model |
| 13 | + |
| 14 | +try: # Not all users will want NWB export, so dependency not in requirements. |
| 15 | + from dlc2nwb.utils import convert_h5_to_nwb, write_subject_to_nwb |
| 16 | +except ImportError: |
| 17 | + raise ImportError( |
| 18 | + "The package `dlc2nwb` is missing. Please run `pip install dlc2nwb`." |
| 19 | + ) |
| 20 | + |
| 21 | +logger = logging.getLogger("datajoint") |
| 22 | + |
| 23 | + |
| 24 | +def dlc_session_to_nwb(keys, use_element_session=True, session_kwargs=None): |
| 25 | + """Using keys from PoseEstimation table, save DLC's h5 output to NWB. |
| 26 | +
|
| 27 | + Calls DLC2NWB to export NWB file using current h5 on disk. If use_element_session, |
| 28 | + calls NWB export function from Elements for lab, animal and session, passing |
| 29 | + session_kwargs. Saves output based on naming convention in DLC2NWB. If output path |
| 30 | + already exists, returns output path without making changes to the file. |
| 31 | + NOTE: does not support multianimal exports |
| 32 | +
|
| 33 | + Parameters |
| 34 | + ---------- |
| 35 | + keys: One or more keys from model.PoseEstimation |
| 36 | + use_element_session: Optional. If True, call NWB export from Element Session |
| 37 | + session_kwargs: Optional. Additional keyword arguments for Element Session export |
| 38 | +
|
| 39 | + Returns output path of saved file |
| 40 | + """ |
| 41 | + if not isinstance(keys, abc.Sequence): # Ensure list for following loop |
| 42 | + keys = [keys] |
| 43 | + |
| 44 | + for key in keys: |
| 45 | + write_file = True |
| 46 | + subject_id = key["subject"] |
| 47 | + output_dir = model.PoseEstimationTask.infer_output_dir(key) |
| 48 | + config_file = str(output_dir / "dj_dlc_config.yaml") |
| 49 | + video_name = Path((model.VideoRecording.File & key).fetch1("file_path")).stem |
| 50 | + h5file = next(output_dir.glob(f"{video_name}*h5")) |
| 51 | + output_path = h5file.replace(".h5", f"_{subject_id}.nwb") # DLC2NWB convention |
| 52 | + |
| 53 | + if Path(output_path).exists(): |
| 54 | + logger.warning(f"Skipping {subject_id}. NWB already exists.") |
| 55 | + write_file = False |
| 56 | + |
| 57 | + # Use standard DLC2NWB export |
| 58 | + if write_file and not use_element_session: |
| 59 | + output_path = convert_h5_to_nwb(config_file, h5file, subject_id) |
| 60 | + |
| 61 | + # Pass Element Session export items in export |
| 62 | + if write_file and use_element_session: |
| 63 | + from element_session.export.nwb import session_to_nwb |
| 64 | + |
| 65 | + session_nwb = session_to_nwb(key, **session_kwargs) # call session export |
| 66 | + dlc_nwb = write_subject_to_nwb(session_nwb, h5file, subject_id, config_file) |
| 67 | + # warnings filter from DLC2NWB |
| 68 | + with warnings.catch_warnings(), NWBHDF5IO(output_path, mode="w") as io: |
| 69 | + warnings.filterwarnings("ignore", category=DtypeConversionWarning) |
| 70 | + io.write(dlc_nwb) |
| 71 | + |
| 72 | + return output_path |
0 commit comments