diff --git a/src/cai_lab_to_nwb/zaki_2024/interfaces/__init__.py b/src/cai_lab_to_nwb/zaki_2024/interfaces/__init__.py index 5dfc5b5..9ea686e 100644 --- a/src/cai_lab_to_nwb/zaki_2024/interfaces/__init__.py +++ b/src/cai_lab_to_nwb/zaki_2024/interfaces/__init__.py @@ -3,3 +3,4 @@ from .minian_interface import MinianSegmentationInterface, MinianMotionCorrectionInterface from .zaki_2024_sleep_classification_interface import Zaki2024SleepClassificationInterface from .miniscope_imaging_interface import MiniscopeImagingInterface +from .zaki_2024_shock_stimuli_interface import Zaki2024ShockStimuliInterface diff --git a/src/cai_lab_to_nwb/zaki_2024/interfaces/miniscope_imaging_interface.py b/src/cai_lab_to_nwb/zaki_2024/interfaces/miniscope_imaging_interface.py index eeda34f..16f3c08 100644 --- a/src/cai_lab_to_nwb/zaki_2024/interfaces/miniscope_imaging_interface.py +++ b/src/cai_lab_to_nwb/zaki_2024/interfaces/miniscope_imaging_interface.py @@ -352,6 +352,7 @@ def add_to_nwbfile( photon_series_index: int = 0, stub_test: bool = False, stub_frames: int = 100, + always_write_timestamps: bool = True, ): from ndx_miniscope.utils import add_miniscope_device @@ -379,4 +380,5 @@ def add_to_nwbfile( metadata=metadata, photon_series_type=photon_series_type, photon_series_index=photon_series_index, + always_write_timestamps=always_write_timestamps, ) diff --git a/src/cai_lab_to_nwb/zaki_2024/interfaces/zaki_2024_shock_stimuli_interface.py b/src/cai_lab_to_nwb/zaki_2024/interfaces/zaki_2024_shock_stimuli_interface.py new file mode 100644 index 0000000..3ad48d8 --- /dev/null +++ b/src/cai_lab_to_nwb/zaki_2024/interfaces/zaki_2024_shock_stimuli_interface.py @@ -0,0 +1,50 @@ +"""Primary class for converting experiment-specific behavior.""" + +from pynwb.file import NWBFile + +from neuroconv.basedatainterface import BaseDataInterface +from neuroconv.utils import DeepDict +from typing import Optional, List +from pynwb.epoch import TimeIntervals + + +class Zaki2024ShockStimuliInterface(BaseDataInterface): + """Adds annotated events of shock times.""" + + keywords = ["behavior", "sleep stages"] + + def __init__(self, verbose: bool = False): + + self.verbose = verbose + super().__init__() + + def get_metadata(self) -> DeepDict: + # Automatically retrieve as much metadata as possible from the source files available + metadata = super().get_metadata() + + return metadata + + def add_to_nwbfile( + self, + nwbfile: NWBFile, + shock_amplitude: float, + shock_times: list, + shock_duration: float, + metadata: Optional[dict] = None, + ): + + description = ( + "During aversive encoding, after a baseline period of 2 min, mice received three 2 s foot shocks " + "of either amplitude 0.25 mA (low-shock) or 1.5 mA (high-shock), with an intershock interval of 1 min. " + "All testing was done in Med Associates chambers. " + ) + + shock_stimuli = TimeIntervals(name="ShockStimuli", description=description) + column_description = "Shock amplitude in mA" + shock_stimuli.add_column(name="shock_amplitude", description=column_description) + for start_time in shock_times: + shock_stimuli.add_interval( + start_time=start_time, stop_time=start_time + shock_duration, shock_amplitude=shock_amplitude + ) + + nwbfile.add_stimulus(shock_stimuli) diff --git a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_all_sessions.py b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_all_sessions.py index b2e382e..71eb831 100644 --- a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_all_sessions.py +++ b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_all_sessions.py @@ -95,6 +95,7 @@ def get_session_to_nwb_kwargs_per_session( # This can be a specific list with hard-coded sessions, a path expansion or any conversion specific logic that you might need ##### import pandas as pd + import re subjects_df = pd.read_excel(data_dir_path / "Ca_EEG_Design.xlsx") subjects = subjects_df["Mouse"] @@ -104,6 +105,14 @@ def get_session_to_nwb_kwargs_per_session( if session_times_file_path.is_file(): session_times_df = pd.read_csv(session_times_file_path) for task in session_times_df["Session"]: + if task == "FC": + shock_amplitude = subjects_df["Amplitude"][subjects_df["Mouse"] == subject_id].to_numpy()[0] + shock_amplitude = float(re.findall(r"[-+]?\d*\.\d+|\d+", shock_amplitude)[0]) + shock_stimulus = dict( + shock_times=[120.0, 180.0, 240.0], shock_amplitude=shock_amplitude, shock_duration=2.0 + ) + else: + shock_stimulus = None session_id = subject_id + "_" + task session_row = session_times_df[session_times_df["Session"] == task].iloc[0] date_str = session_row["Date"] @@ -115,6 +124,7 @@ def get_session_to_nwb_kwargs_per_session( session_id=session_id, date_str=date_str, time_str=time_str, + shock_stimulus=shock_stimulus, ) ) else: diff --git a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_session.py b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_session.py index 2ab6815..97dc377 100644 --- a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_session.py +++ b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_convert_session.py @@ -93,6 +93,7 @@ def session_to_nwb( include_sleep_classification: bool = True, include_behavioral_video: bool = True, include_eeg_emg_signals: bool = True, + shock_stimulus: dict = None, ): print(f"Converting session {session_id}") if verbose: @@ -218,6 +219,14 @@ def session_to_nwb( elif verbose and not sleep_classification_file_path.is_file(): print(f"No sleep classification output csv file found at {sleep_classification_file_path}") + # Add Shock Stimuli times for FC sessions + if shock_stimulus is not None: + + source_data.update(ShockStimuli=dict()) + conversion_options.update( + ShockStimuli=shock_stimulus, + ) + converter = Zaki2024NWBConverter(source_data=source_data) # Add datetime to conversion @@ -256,7 +265,7 @@ def session_to_nwb( # Parameters for conversion data_dir_path = Path("D:/") subject_id = "Ca_EEG3-4" - task = "OfflineDay1Session1" + task = "FC" session_id = subject_id + "_" + task output_dir_path = Path("D:/cai_lab_conversion_nwb/") stub_test = False @@ -265,6 +274,7 @@ def session_to_nwb( session_row = df[df["Session"] == task].iloc[0] date_str = session_row["Date"] time_str = session_row["Time"] + shock_stimulus = dict(shock_times=[120.0, 180.0, 240.0], shock_amplitude=0.25, shock_duration=2.0) session_to_nwb( data_dir_path=data_dir_path, output_dir_path=output_dir_path, @@ -273,4 +283,5 @@ def session_to_nwb( session_id=session_id, date_str=date_str, time_str=time_str, + shock_stimulus=shock_stimulus, ) diff --git a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_metadata.yaml b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_metadata.yaml index bf535e7..ccc26fd 100644 --- a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_metadata.yaml +++ b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_metadata.yaml @@ -1,44 +1,48 @@ NWBFile: keywords: - hippocampus - - memory integration + - learning - memory-linking - ensemble - reactivation - - co-firing + - co-activity - offline periods - - sleep - - stress - - PTSD + - aversive related_publications: - - https://www.biorxiv.org/content/10.1101/2023.03.13.532469v2 + - https://doi.org/10.1038/s41586-024-08168-4 session_description: - A rich text description of the experiment. Can also just be the abstract of the publication. + In memory-linking behavioural experiments, mice were exposed to the neutral context for 10 min to explore. + During aversive encoding, after a baseline period of 2 min, mice received three 2 s foot shocks of either amplitude + 0.25 mA (low-shock) or 1.5 mA (high-shock), with an intershock interval of 1 min. + Then, 30 s after the final shock, the mice were removed and returned to the vivarium. + On the next 3 days, the mice were tested in the previously experienced aversive and neutral contexts, + as well as a completely novel context that they had not been exposed to previously, for 5 min each. + The features of the neutral and novel contexts were counter-balanced and were made up of different olfactory, + auditory, lighting and tactile cues. + The aversive context was always the same with distinct cues from the neutral and novel contexts. + In the low- versus high-shock experiments mice were tested in the aversive context first, + followed by testing in the neutral and novel context counter-balanced; + half of the mice received neutral recall and then novel-context exposure the next day, + and the other half received novel-context exposure and then neutral recall. + experiment_description: + Simultaneous calcium imaging with Miniscopes and EEG/EMG experiment during retrospective memory-linking behavioral paradigm, + to test whether ensemble co-reactivation is sleep-state specific institution: Icahn School of Medicine at Mount Sinai lab: Cai experimenter: - - Cai, Denise - - Morales-Rodriguez, Denisse - - Bacon, Madeline E. - - Ko, BumJin - - Francisco, Taylor R. - - LaBanca, Alexa R. - - Sompolpong, Patlapa - - Dong, Zhe - - Lamsifer, Sophia - - Chen, Hung-Tu - - Carrillo Segura, Simón - - Christenson Wick, Zoé - - Silva, Alcino J. - - Rajan, Kanaka - - van der Meer, Matthijs - - Fenton, André - - Shuman, Tristan - Zaki, Yosif + surgery: + Mice were anaesthetized with 1 to 2% isoflurane for surgical procedures and placed into a stereotaxic frame (David Kopf Instruments). + Eye ointment was applied to prevent desiccation, and the mice were kept on a heated pad to prevent hypothermia. + Surgery was performed using aseptic technique. After surgery, carprofen (5mg per kg) was administered every day for the following 3 days, + and ampicillin (20mg per kg) was administered every day for the next 7days. + For calcium imaging experiments, dexamethasone (0.2mg per kg) was also administered for the following 7days. + virus: + AAV1-Syn-GCaMP6f was injected into dorsal CA1 of the hippocampus on the right hemisphere (AP, −2 mm; ML, +1.5 mm; DV, −1.2 mm) Subject: species: Mus musculus age: P12W/P15W # in ISO 8601, such as "P1W2D" - sex: U # One of M, F, U, or O + sex: M Ophys: OnePhotonSeries: - name: OnePhotonSeries diff --git a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_nwbconverter.py b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_nwbconverter.py index d4784ef..8ef2c16 100644 --- a/src/cai_lab_to_nwb/zaki_2024/zaki_2024_nwbconverter.py +++ b/src/cai_lab_to_nwb/zaki_2024/zaki_2024_nwbconverter.py @@ -15,6 +15,7 @@ Zaki2024SleepClassificationInterface, MiniscopeImagingInterface, MinianMotionCorrectionInterface, + Zaki2024ShockStimuliInterface, ) @@ -30,6 +31,7 @@ class Zaki2024NWBConverter(NWBConverter): MultiEDFSignals=Zaki2024MultiEDFInterface, FreezingBehavior=EzTrackFreezingBehaviorInterface, Video=VideoInterface, + ShockStimuli=Zaki2024ShockStimuliInterface, )