diff --git a/src/silverlabnwb/header.py b/src/silverlabnwb/header.py index cfdf661..6aef430 100644 --- a/src/silverlabnwb/header.py +++ b/src/silverlabnwb/header.py @@ -131,6 +131,14 @@ def determine_trial_times(self): """ raise NotImplementedError + def get_subject_info(self): + """Extract information about the subject if there is any in the header. + + Return an empty string if no information is found. This is always the case in legacy LabView versions, + and sometimes the case in newer LabView versions. + """ + return "" + def get_raw_fields(self): """Get the fields of the header as directly read from the file. @@ -253,3 +261,10 @@ def determine_trial_times(self): end = None # determine final 'end' later from speed data trial_times.append((start, end)) return trial_times + + def get_subject_info(self): + return "\n".join( + f'{field}: {value}' + for field, value in self['BIOLOGY INFORMATION'].items() + if value + ) diff --git a/src/silverlabnwb/nwb_file.py b/src/silverlabnwb/nwb_file.py index 3172f57..02d2b82 100644 --- a/src/silverlabnwb/nwb_file.py +++ b/src/silverlabnwb/nwb_file.py @@ -74,6 +74,7 @@ def __init__(self, nwb_path, mode='r', verbose=True): self.custom_silverlab_dict = dict() self.labview_version = None self.imaging_info = None + self.subject = None self.trial_times = None self.compress = None @@ -220,6 +221,10 @@ def add_core_metadata(self): # even though it is still stored under /general/stimulus if 'stimulus' in self.experiment: self.add_general_info('stimulus_notes', self.experiment['stimulus']) + # If both metadata and header have a non-empty subject entry, the header gets priority. + # If neither have an entry, pynwb defaults to not writing a subject field in the file. + if self.subject: + self.add_subject(self.subject) if 'subject' in self.experiment: self.add_subject(self.experiment['subject']) # Update the file on disk: diff --git a/tests/data/real life Experiment Header v231 pointing.ini b/tests/data/real life Experiment Header v231 pointing.ini index 13e4ffc..32ccc6d 100644 --- a/tests/data/real life Experiment Header v231 pointing.ini +++ b/tests/data/real life Experiment Header v231 pointing.ini @@ -175,6 +175,11 @@ Integral Scale Z = 20.000 Scan Interval = 2.000 Ref Plot Refresh Rate = 0.000 +[BIOLOGY INFORMATION] +Animal Code or Name = "" +Animal DoB = "" +Animal Age = "" + [Intertrial FIFO Times] 0.000000 16.428930 1.000000 32.850058 diff --git a/tests/data/synthetic experiment Header v231 no last time.ini b/tests/data/synthetic experiment Header v231 no last time.ini index 0b3f38f..a11be5d 100644 --- a/tests/data/synthetic experiment Header v231 no last time.ini +++ b/tests/data/synthetic experiment Header v231 no last time.ini @@ -17,6 +17,11 @@ Functional Mode = "Patch" [VOLUME IMAGING] Functional Mode = "Point" +[BIOLOGY INFORMATION] +Animal Code or Name = "" +Animal DoB = "" +Animal Age = "" + [Intertrial FIFO Times] 0.000000 0.000000 1.000000 12.345678 diff --git a/tests/data/synthetic experiment Header v231.ini b/tests/data/synthetic experiment Header v231.ini index 9d6c3e9..ef0b08a 100644 --- a/tests/data/synthetic experiment Header v231.ini +++ b/tests/data/synthetic experiment Header v231.ini @@ -17,6 +17,12 @@ Functional Mode = "Patch" [VOLUME IMAGING] Functional Mode = "Point" +[BIOLOGY INFORMATION] +Animal Code or Name = "Test1" +Animal DoB = "" +Region of brain imaged = "crus" + + [Intertrial FIFO Times] 0.000000 0.000000 1.000000 12.345678 diff --git a/tests/test_header.py b/tests/test_header.py index c82309d..de38e99 100644 --- a/tests/test_header.py +++ b/tests/test_header.py @@ -59,6 +59,15 @@ def test_pre2018_trial_times_raises_error(self, header): with pytest.raises(NotImplementedError): header.determine_trial_times() + @pytest.mark.parametrize("header, expected_subject", + [(synthetic_header_path_v231, "Animal Code or Name: Test1\nRegion of brain imaged: crus"), + (synthetic_header_path_v231_no_last_time, ""), + (synthetic_header_path_pre2018, ""), + (real_life_header_path_v231_pointing, "")], + indirect=["header"]) + def test_subject_info(self, header, expected_subject): + assert header.get_subject_info() == expected_subject + def test_unrecognised_line_causes_warning(self): with pytest.warns(UserWarning) as list_of_warnings: LabViewHeader.from_file(os.path.join("tests", "data", self.header_with_unrecognised_line_path))