From a838c46a1fcb8fff1e93bd72c19c00ed0c4eb2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20Cl=C3=A9net?= <117362283+bclenet@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:24:02 +0200 Subject: [PATCH] Task information (#117) * [BUG] inside unit_tests workflow * [ENH] A class to parse task data * [TEST] making tests pass * [DOC] update for narps_open.data --- docs/data.md | 36 +++++++++++++++ narps_open/data/task.py | 27 +++++++++++ tests/data/test_task.py | 57 ++++++++++++++++++++++++ tests/test_data/data/task/task-info.json | 12 +++++ 4 files changed, 132 insertions(+) create mode 100644 narps_open/data/task.py create mode 100644 tests/data/test_task.py create mode 100644 tests/test_data/data/task/task-info.json diff --git a/docs/data.md b/docs/data.md index 1e6b4fc3..e2e84da1 100644 --- a/docs/data.md +++ b/docs/data.md @@ -94,3 +94,39 @@ python narps_open/utils/results -r -t 2T6S C88N L1A8 The collections are also available [here](https://zenodo.org/record/3528329/) as one release on Zenodo that you can download. Each team results collection is kept in the `data/results/orig` directory, in a folder using the pattern `_` (e.g.: `4881_2T6S` for the 2T6S team). + +## Access NARPS data + +Inside `narps_open.data`, several modules allow to parse data from the NARPS file, so it's easier to use it inside the Narps Open Pipelines project. These are : + +### `narps_open.data.description` +Get textual description of the pipelines, as written by the teams (see [docs/description.md](/docs/description.md)). + +### `narps_open.data.results` +Get the result collections, as described earlier in this file. + +### `narps_open.data.participants` +Get the participants data (parses the `data/original/ds001734/participants.tsv` file) as well as participants subsets to perform analyses on lower numbers of images. + +### `narps_open.data.task` +Get information about the task (parses the `data/original/ds001734/task-MGT_bold.json` file). Here is an example how to use it : + +```python +from narps_open.data.task import TaskInformation + +task_info = TaskInformation() # task_info is a dict + +# All available keys +print(task_info.keys()) +# dict_keys(['TaskName', 'Manufacturer', 'ManufacturersModelName', 'MagneticFieldStrength', 'RepetitionTime', 'EchoTime', 'FlipAngle', 'MultibandAccelerationFactor', 'EffectiveEchoSpacing', 'SliceTiming', 'BandwidthPerPixelPhaseEncode', 'PhaseEncodingDirection', 'TaskDescription', 'CogAtlasID', 'NumberOfSlices', 'AcquisitionTime', 'TotalReadoutTime']) + +# Original data +print(task_info['TaskName']) +print(task_info['Manufacturer']) +print(task_info['RepetitionTime']) # And so on ... + +# Derived data +print(task_info['NumberOfSlices']) +print(task_info['AcquisitionTime']) +print(task_info['TotalReadoutTime']) +``` diff --git a/narps_open/data/task.py b/narps_open/data/task.py new file mode 100644 index 00000000..f3e86803 --- /dev/null +++ b/narps_open/data/task.py @@ -0,0 +1,27 @@ +#!/usr/bin/python +# coding: utf-8 + +""" A mdoule to parse task data from NARPS for the narps_open package """ + +from os.path import join +from json import load + +from narps_open.utils.configuration import Configuration +from narps_open.utils.singleton import SingletonMeta + +class TaskInformation(dict, metaclass=SingletonMeta): + """ This class allows to access information about the task performed in NARPS """ + + task_information_file = join(Configuration()['directories']['dataset'], 'task-MGT_bold.json') + + def __init__(self): + super().__init__() + + # Load information from the task-MGT_bold.json file + with open(self.task_information_file, 'rb') as file: + self.update(load(file)) + + # Compute derived information + self['NumberOfSlices'] = len(self['SliceTiming']) + self['AcquisitionTime'] = self['RepetitionTime'] / self['NumberOfSlices'] + self['TotalReadoutTime'] = self['NumberOfSlices'] * self['EffectiveEchoSpacing'] diff --git a/tests/data/test_task.py b/tests/data/test_task.py new file mode 100644 index 00000000..8b6860dd --- /dev/null +++ b/tests/data/test_task.py @@ -0,0 +1,57 @@ +#!/usr/bin/python +# coding: utf-8 + +""" Tests of the 'narps_open.data.task' module. + +Launch this test with PyTest + +Usage: +====== + pytest -q test_task.py + pytest -q test_task.py -k +""" +from os.path import join + +from pytest import mark, fixture + +from narps_open.utils.configuration import Configuration +import narps_open.data.task as task + +@fixture(scope='function', autouse=True) +def mock_task_data(mocker): + """ Patch the json.load method to mock task data """ + mocker.patch.object( + task.TaskInformation, 'task_information_file', + join(Configuration()['directories']['test_data'], 'data', 'task', 'task-info.json') + ) + +class TestTaskInformation: + """ A class that contains all the unit tests for the TaskInformation class.""" + + @staticmethod + @mark.unit_test + def test_accessing(): + """ Check that task information is reachable """ + + assert task.TaskInformation()['RepetitionTime'] == 1 + assert len(task.TaskInformation()['SliceTiming']) == 6 + + @staticmethod + @mark.unit_test + def test_singleton(): + """ Check that TaskInformation is a singleton. """ + + obj1 = task.TaskInformation() + obj2 = task.TaskInformation() + + assert id(obj1) == id(obj2) + + @staticmethod + @mark.unit_test + def test_derived(): + """ Test the derived values of a TaskInformation object """ + + task_info = task.TaskInformation() + assert task_info['NumberOfSlices'] == 6 + assert task_info['AcquisitionTime'] == 1 / 6 + assert task_info['TotalReadoutTime'] == 12 diff --git a/tests/test_data/data/task/task-info.json b/tests/test_data/data/task/task-info.json new file mode 100644 index 00000000..7927183d --- /dev/null +++ b/tests/test_data/data/task/task-info.json @@ -0,0 +1,12 @@ +{ + "RepetitionTime": 1, + "EffectiveEchoSpacing": 2, + "SliceTiming": [ + 0, + 0.4375, + 0.875, + 0.3125, + 0.75, + 0.1875 + ] +} \ No newline at end of file