[MAINT]: Regular repository maintenance #337

Merged
synchon merged 13 commits from chore/repo-maint into main 2024-06-03 13:37:46 +00:00
126 changed files with 720 additions and 186 deletions

View file

@ -4,7 +4,7 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: check-ast
- id: check-docstring-first
@ -20,14 +20,14 @@ repos:
rev: v0.16
hooks:
- id: validate-pyproject
- repo: https://github.com/psf/black
rev: 24.1.1
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 24.4.2
hooks:
- id: black
exclude: ^(docs/|examples/|tools/)
args: [--check]
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.15
rev: v0.4.2
hooks:
- id: ruff
types_or: [python, jupyter]
@ -38,7 +38,7 @@ repos:
hooks:
- id: codespell
exclude: ^(.github/|docs/)
args: [--config, tox.ini]
args: [--toml, pyproject.toml]
- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
@ -47,3 +47,10 @@ repos:
- id: rst-backticks
- id: rst-directive-colons
- id: rst-inline-touching-normal
- repo: https://github.com/adamchainz/blacken-docs
rev: "1.16.0"
hooks:
- id: blacken-docs
additional_dependencies:
- black==24.4.2
args: [-l 79]

View file

@ -0,0 +1 @@
Update ``pre-commit`` dependency versions, add ``blacken-docs`` to ``pre-commit``, add ``__all__`` for modules, sub-packages and package, update ``ruff`` and ``pytest`` configs in ``pyproject.toml`` by `Synchon Mandal`_

View file

@ -70,10 +70,7 @@ with the DMN. Here, we use the DMN coordinates used in a
.. code-block:: python
dmn_coords = np.array(
[[0, -52, 18],
[-46, -68, 32],
[46, -68, 32],
[1, 50, -5]]
[[0, -52, 18], [-46, -68, 32], [46, -68, 32], [1, 50, -5]]
)
voi_names = [
"Posterior Cingulate Cortex",
@ -90,10 +87,7 @@ simply use this to register our coordinates:
.. code-block:: python
register_coordinates(
name="DMNCustom",
coordinates=dmn_coords,
voi_names=voi_names,
space="MNI"
name="DMNCustom", coordinates=dmn_coords, voi_names=voi_names, space="MNI"
)
Now, when we run this script, ``junifer`` registers these coordinates and we can

View file

@ -115,14 +115,14 @@ For example, in our BIDS example, the variables will be:
types = ["T1w", "BOLD"]
patterns = {
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
replacements = ["subject", "session"]
@ -144,25 +144,24 @@ With the variables defined above, we can create our DataGrabber and name it
class ExampleBIDSDataGrabber(PatternDataGrabber):
def __init__(self, datadir: str | Path) -> None:
types = ["T1w", "BOLD"]
patterns = {
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
replacements = ["subject", "session"]
super().__init__(
datadir=datadir,
types=types,
patterns=patterns,
replacements=replacements,
datadir=datadir,
types=types,
patterns=patterns,
replacements=replacements,
)
Our DataGrabber is ready to be used by ``junifer``. However, it is still unknown
@ -180,25 +179,24 @@ use the :func:`.register_datagrabber` decorator.
@register_datagrabber
class ExampleBIDSDataGrabber(PatternDataGrabber):
def __init__(self, datadir: str | Path) -> None:
types = ["T1w", "BOLD"]
patterns = {
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
replacements = ["subject", "session"]
super().__init__(
datadir=datadir,
types=types,
patterns=patterns,
replacements=replacements,
datadir=datadir,
types=types,
patterns=patterns,
replacements=replacements,
)
@ -267,29 +265,28 @@ And we can create our DataGrabber:
@register_datagrabber
class ExampleBIDSDataGrabber(PatternDataladDataGrabber):
def __init__(self) -> None:
types = ["T1w", "BOLD"]
patterns = {
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
"T1w": {
"pattern": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"pattern": "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
replacements = ["subject", "session"]
uri = "https://gin.g-node.org/juaml/datalad-example-bids"
rootdir = "example_bids_ses"
super().__init__(
datadir=None,
uri=uri,
rootdir=rootdir,
types=types,
patterns=patterns,
replacements=replacements,
datadir=None,
uri=uri,
rootdir=rootdir,
types=types,
patterns=patterns,
replacements=replacements,
)
This approach can be used directly from the YAML, like so:
@ -391,17 +388,17 @@ and ``session``, we will use them as parameters of ``get_item``:
.. code-block:: python
def get_item(self, subject: str, session: str) -> dict[str, dict[str, str]]:
out = {
"T1w": {
"path": f"{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"path": f"{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
return out
out = {
"T1w": {
"path": f"{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"path": f"{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
return out
The second method, ``get_elements``, needs to return a list of all the elements
@ -415,16 +412,16 @@ need to remember that for session *ses-03* there is no BOLD data.
def get_elements(self) -> list[str]:
subjects = ["sub-01", "sub-02", "sub-03"]
sessions = ["ses-01", "ses-02"]
subjects = ["sub-01", "sub-02", "sub-03"]
sessions = ["ses-01", "ses-02"]
# If we are not working on BOLD data, we can add "ses-03"
if "BOLD" not in self.types:
sessions.append("ses-03")
elements = []
for subject, element in product(subjects, sessions):
elements.append({"subject": subject, "session": session})
return elements
# If we are not working on BOLD data, we can add "ses-03"
if "BOLD" not in self.types:
sessions.append("ses-03")
elements = []
for subject, element in product(subjects, sessions):
elements.append({"subject": subject, "session": session})
return elements
And finally, we can implement the ``get_element_keys`` method. This method needs
@ -435,7 +432,7 @@ method, in the same order.
.. code-block:: python
def get_element_keys(self) -> list[str]:
return ["subject", "session"]
return ["subject", "session"]
So, to summarise, our DataGrabber will look like this:
@ -448,35 +445,36 @@ So, to summarise, our DataGrabber will look like this:
@register_datagrabber
class ExampleBIDSDataGrabber(BaseDataGrabber):
def get_item(
self, subject: str, session: str
) -> dict[str, dict[str, str]]:
out = {
"T1w": {
"path": f"{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"path": f"{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
return out
def get_item(self, subject: str, session: str) -> dict[str, dict[str, str]]:
out = {
"T1w": {
"path": f"{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
"space": "native",
},
"BOLD": {
"path": f"{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
},
}
return out
def get_elements(self) -> list[str]:
subjects = ["sub-01", "sub-02", "sub-03"]
sessions = ["ses-01", "ses-02"]
def get_elements(self) -> list[str]:
subjects = ["sub-01", "sub-02", "sub-03"]
sessions = ["ses-01", "ses-02"]
# If we are not working on BOLD data, we can add "ses-03"
if "BOLD" not in self.types:
sessions.append("ses-03")
elements = []
for subject in subjects:
for session in sessions:
elements.append({"subject": subject, "session": session})
return elements
# If we are not working on BOLD data, we can add "ses-03"
if "BOLD" not in self.types:
sessions.append("ses-03")
elements = []
for subject in subjects:
for session in sessions:
elements.append({"subject": subject, "session": session})
return elements
def get_element_keys(self) -> list[str]:
return ["subject", "session"]
def get_element_keys(self) -> list[str]:
return ["subject", "session"]
Optional: Using datalad
~~~~~~~~~~~~~~~~~~~~~~~
@ -522,26 +520,24 @@ this:
.. code-block:: python
def get_item(
self, subject: str, session: str
) -> dict:
out = {
"BOLD": {
"path": f"{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
"confounds": {
"path": f"{subject}/{session}/func/{subject}_{session}_confounds.tsv",
"format": "adhoc",
"mappings": {
"fmriprep": {
"variable1": "rot_x",
"variable2": "rot_z",
"variable3": "rot_y",
},
},
},
},
}
def get_item(self, subject: str, session: str) -> dict:
out = {
"BOLD": {
"path": f"{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz",
"space": "MNI152NLin6Asym",
"confounds": {
"path": f"{subject}/{session}/func/{subject}_{session}_confounds.tsv",
"format": "adhoc",
"mappings": {
"fmriprep": {
"variable1": "rot_x",
"variable2": "rot_z",
"variable3": "rot_y",
},
},
},
},
}
.. note::

View file

@ -93,6 +93,7 @@ that it shows the problem a bit better and how we solve it:
self, using: str, reference: str, on: Union[List[str], str]
) -> None:
# validation and setting up
...
Here, you see a new class attribute ``_CONDITIONAL_DEPENDENCIES`` which is a
@ -129,6 +130,7 @@ similar. ``FSLWarper`` looks like this (only the relevant part is shown here):
extra_input: Dict[str, Any],
) -> Dict[str, Any]:
# implementation
...
Here you can see the familiar ``_DEPENDENCIES`` and ``_EXT_DEPENDENCIES`` class
attributes. The validation process starts by looking up the ``using`` value of

View file

@ -82,10 +82,10 @@ parcellation to use. Thus, we can define the ``__init__`` method as follows:
.. code-block:: python
def __init__(
self,
parcellation: str,
on: str | list[str] | None = None,
name: str | None = None,
self,
parcellation: str,
on: str | list[str] | None = None,
name: str | None = None,
) -> None:
self.parcellation = parcellation
super().__init__(on=on, name=name)
@ -137,9 +137,9 @@ the ``store`` method.
def compute(
self,
input: dict[str, Any],
extra_input: dict[str, Any] | None = None,
self,
input: dict[str, Any],
extra_input: dict[str, Any] | None = None,
) -> dict[str, Any]:
# Get the data
data = input["data"]
@ -207,10 +207,10 @@ Finally, we need to register the Marker using the ``@register_marker`` decorator
_DEPENDENCIES = {"nilearn", "numpy"}
def __init__(
self,
parcellation: str,
on: str | list[str] | None = None,
name: str | None = None,
self,
parcellation: str,
on: str | list[str] | None = None,
name: str | None = None,
) -> None:
self.parcellation = parcellation
super().__init__(on=on, name=name)
@ -225,9 +225,9 @@ Finally, we need to register the Marker using the ``@register_marker`` decorator
return "vector"
def compute(
self,
input: dict[str, Any],
extra_input: dict[str, Any] | None = None,
self,
input: dict[str, Any],
extra_input: dict[str, Any] | None = None,
) -> dict[str, Any]:
# Get the data
data = input["data"]
@ -269,7 +269,6 @@ Template for a custom Marker
@register_marker
class TemplateMarker(BaseMarker):
def __init__(self, on=None, name=None):
# TODO: add marker-specific parameters
super().__init__(on=on, name=name)

View file

@ -83,7 +83,7 @@ look like this:
name="my_custom_parcellation",
parcellation_path=path_to_parcellation,
parcels_labels=my_labels,
space="MNI152NLin2009cAsym"
space="MNI152NLin2009cAsym",
)
We can run this code and it seems to work, however, how can we actually

View file

@ -43,9 +43,11 @@ For input we can accept ``T1w``, ``T2w`` and ``BOLD``
...
def get_valid_inputs(self) -> list[str]:
return ["T1w", "T2w", "BOLD"]
...
The output definition of the Preprocessor is unused now but is kept for
@ -55,9 +57,11 @@ completeness.
...
def get_output_type(self, input_type: str) -> str:
return input_type
...
.. _extending_preprocessors_init:
@ -90,6 +94,7 @@ you configure it. Our class will have the following arguments:
...
def __init__(
self,
fwhm: int | float | ArrayLike | Literal["fast"] | None,
@ -98,6 +103,7 @@ you configure it. Our class will have the following arguments:
self.fwhm = fwhm
super().__init__(on=on)
...
.. caution::
@ -147,15 +153,18 @@ and it has two return values:
...
def preprocess(
self,
input: dict[str, Any],
extra_input: dict[str, Any] | None = None,
) -> tuple[dict[str, Any], dict[str, Any] | None]:
input["data"] = nimg.smooth_img(imgs=input["data"], fwhm=self.fwhm)
return input, None
input["data"] = nimg.smooth_img(imgs=input["data"], fwhm=self.fwhm)
return input, None
...
...
Step 4: Finalise the Preprocessor
---------------------------------

View file

@ -12,7 +12,7 @@ This is the *object* that traverses the steps of the pipeline. It is indeed a
dictionary of dictionaries. The first level of keys are the :ref:`data types <data_types>`
and the values are the corresponding information as dictionaries.
.. code-block:: python
.. code-block::
{'BOLD': {...}, 'T1w': {...}}
@ -24,7 +24,7 @@ The :ref:`Data Grabber <datagrabber>` step adds the ``path`` second-level key
which gives the path to the file containing the data. The ``meta`` key in this
step only contains information about the DataGrabber used.
.. code-block:: python
.. code-block::
{'BOLD': {'meta': {'datagrabber': {'class': 'SPMAuditoryTestingDataGrabber',
'types': ['BOLD', 'T1w']},
@ -41,7 +41,7 @@ The :ref:`Data Reader <datareader>` step adds the ``data`` second-level key
which is the actual data loaded into memory. The ``meta`` key in this step
adds information about the DataReader used to read the data.
.. code-block:: python
.. code-block::
{'BOLD': {'data': <nibabel.nifti1.Nifti1Image object at 0x16b5d8910>,
'meta': {'datagrabber': {'class': 'SPMAuditoryTestingDataGrabber',
@ -58,6 +58,7 @@ adds information about the DataReader used to read the data.
'element': {'subject': 'sub001'}},
'path': PosixPath('/var/folders/dv/2lbr8f8j0q12zrx3mz3ll5m40000gp/T/tmpe49321ce/sub001_T1w.nii.gz')}}
The :ref:`Preprocess <preprocess>` step, if used, modifies the ``data``
second-level key's value and appends the ``meta`` key with information about
the preprocessor.
@ -66,7 +67,7 @@ The :ref:`Marker <marker>` step removes the ``path`` second-level key,
replaces the ``data`` second-level key's value with the marker's computed value
and adds further keys needed for the storage, for example, ``col_names``.
.. code-block:: python
.. code-block::
{'BOLD': {'col_names': ['root_sum_of_squares_ets'],
'data': ...,

View file

@ -69,7 +69,7 @@ Example in python format:
strategy = {
"motion": "basic",
"wm_csf": "full",
"global_signal": "derivatives"
"global_signal": "derivatives",
}
or in YAML format:
@ -85,11 +85,7 @@ The default value is to use all the *noise components* with the ``full`` *confou
.. code-block:: python
strategy = {
"motion": "full",
"wm_csf": "full",
"global_signal": "full"
}
strategy = {"motion": "full", "wm_csf": "full", "global_signal": "full"}
Other Parameters
~~~~~~~~~~~~~~~~

View file

@ -20,3 +20,20 @@ from . import (
onthefly,
)
from ._version import __version__
__all__ = [
"api",
"configs",
"data",
"datagrabber",
"datareader",
"markers",
"pipeline",
"preprocess",
"stats",
"storage",
"utils",
"external",
"onthefly",
]

View file

@ -7,3 +7,6 @@
from . import decorators
from .cli import cli
from .functions import collect, queue, run
__all__ = ["decorators", "cli", "collect", "queue", "run"]

View file

@ -10,6 +10,15 @@ from typing import Type
from ..pipeline.registry import register
__all__ = [
"register_datagrabber",
"register_datareader",
"register_preprocessor",
"register_marker",
"register_storage",
]
def register_datagrabber(klass: Type) -> Type:
"""Register DataGrabber.

View file

@ -23,6 +23,9 @@ from .queue_context import GnuParallelLocalAdapter, HTCondorAdapter
from .utils import yaml
__all__ = ["run", "collect", "queue", "reset", "list_elements"]
def _get_datagrabber(datagrabber_config: Dict) -> BaseDataGrabber:
"""Get DataGrabber.
@ -92,7 +95,7 @@ def run(
datagrabber : dict
DataGrabber to use. Must have a key ``kind`` with the kind of
DataGrabber to use. All other keys are passed to the DataGrabber
init function.
constructor.
markers : list of dict
List of markers to extract. Each marker is a dict with at least two
keys: ``name`` and ``kind``. The ``name`` key is used to name the
@ -102,11 +105,11 @@ def run(
storage : dict
Storage to use. Must have a key ``kind`` with the kind of
storage to use. All other keys are passed to the storage
init function.
constructor.
preprocessors : list of dict, optional
List of preprocessors to use. Each preprocessor is a dict with at
least a key ``kind`` specifying the preprocessor to use. All other keys
are passed to the preprocessor init function (default None).
are passed to the preprocessor constructor (default None).
elements : str or tuple or list of str or tuple, optional
Element(s) to process. Will be used to index the DataGrabber
(default None).
@ -188,7 +191,7 @@ def collect(storage: Dict) -> None:
storage : dict
Storage to use. Must have a key ``kind`` with the kind of
storage to use. All other keys are passed to the storage
init function.
constructor.
"""
storage_params = storage.copy()

View file

@ -14,6 +14,9 @@ from ..utils.logging import logger, raise_error
from .utils import yaml
__all__ = ["parse_yaml"]
def parse_yaml(filepath: Union[str, Path]) -> Dict:
"""Parse YAML.

View file

@ -6,3 +6,6 @@
from .queue_context_adapter import QueueContextAdapter
from .htcondor_adapter import HTCondorAdapter
from .gnu_parallel_local_adapter import GnuParallelLocalAdapter
__all__ = ["QueueContextAdapter", "HTCondorAdapter", "GnuParallelLocalAdapter"]

View file

@ -31,7 +31,7 @@ if [ -d "${var}" ]; then
done
echo "Docker args: ${docker_args[*]}" >&2
echo "Corrected args for afni: ${corrected_args[*]}" >&2
echo "Corrected args for AFNI: ${corrected_args[*]}" >&2
cwd=$(pwd)
cmd="docker run --rm ${docker_args[*]} -v ${cwd}:${cwd} -w ${cwd} afni/afni_make_build ${corrected_args[*]}"

View file

@ -31,7 +31,7 @@ if [ -d "${var}" ]; then
done
echo "Docker args: ${docker_args[*]}" >&2
echo "Corrected args for fsl: ${corrected_args[*]}" >&2
echo "Corrected args for ANTs: ${corrected_args[*]}" >&2
cwd=$(pwd)
cmd="docker run --rm ${docker_args[*]} -v ${cwd}:${cwd} -w ${cwd} antsx/ants ${corrected_args[*]}"

View file

@ -31,7 +31,7 @@ if [ -d "${var}" ]; then
done
echo "Docker args: ${docker_args[*]}" >&2
echo "Corrected args for fsl: ${corrected_args[*]}" >&2
echo "Corrected args for FSL: ${corrected_args[*]}" >&2
cwd=$(pwd)
cmd="docker run --rm ${docker_args[*]} -v ${cwd}:${cwd} -w ${cwd} brainlife/fsl ${corrected_args[*]}"

View file

@ -4,3 +4,6 @@
# License: AGPL
from . import datagrabbers
__all__ = ["datagrabbers"]

View file

@ -10,3 +10,12 @@ from .camcan_vbm import JuselessDataladCamCANVBM
from .ixi_vbm import JuselessDataladIXIVBM
from .ucla import JuselessUCLA
from .ukb_vbm import JuselessDataladUKBVBM
__all__ = [
"JuselessDataladAOMICID1000VBM",
"JuselessDataladCamCANVBM",
"JuselessDataladIXIVBM",
"JuselessUCLA",
"JuselessDataladUKBVBM",
]

View file

@ -11,6 +11,9 @@ from ....api.decorators import register_datagrabber
from ....datagrabber import PatternDataladDataGrabber
__all__ = ["JuselessDataladAOMICID1000VBM"]
@register_datagrabber
class JuselessDataladAOMICID1000VBM(PatternDataladDataGrabber):
"""Concrete implementation for Juseless AOMIC ID1000 VBM data fetching.

View file

@ -12,6 +12,9 @@ from ....api.decorators import register_datagrabber
from ....datagrabber import PatternDataladDataGrabber
__all__ = ["JuselessDataladCamCANVBM"]
@register_datagrabber
class JuselessDataladCamCANVBM(PatternDataladDataGrabber):
"""Concrete implementation for Juseless CamCAN VBM data fetching.

View file

@ -13,6 +13,9 @@ from ....datagrabber import PatternDataladDataGrabber
from ....utils import raise_error
__all__ = ["JuselessDataladIXIVBM"]
@register_datagrabber
class JuselessDataladIXIVBM(PatternDataladDataGrabber):
"""Concrete implementation for Juseless IXI VBM data fetching.

View file

@ -12,6 +12,9 @@ from ....datagrabber import PatternDataGrabber
from ....utils import raise_error
__all__ = ["JuselessUCLA"]
@register_datagrabber
class JuselessUCLA(PatternDataGrabber):
"""Concrete implementation for Juseless UCLA data fetching.

View file

@ -12,6 +12,9 @@ from ....api.decorators import register_datagrabber
from ....datagrabber import PatternDataladDataGrabber
__all__ = ["JuselessDataladUKBVBM"]
@register_datagrabber
class JuselessDataladUKBVBM(PatternDataladDataGrabber):
"""Concrete implementation for Juseless UKB VBM data fetching.

View file

@ -28,3 +28,23 @@ from .masks import (
from .template_spaces import get_template, get_xfm
from . import utils
__all__ = [
"list_coordinates",
"load_coordinates",
"register_coordinates",
"get_coordinates",
"list_parcellations",
"load_parcellation",
"register_parcellation",
"merge_parcellations",
"get_parcellation",
"list_masks",
"load_mask",
"register_mask",
"get_mask",
"get_template",
"get_xfm",
"utils",
]

View file

@ -16,6 +16,14 @@ from ..pipeline import WorkDirManager
from ..utils import logger, raise_error, run_ext_cmd
__all__ = [
"register_coordinates",
"list_coordinates",
"get_coordinates",
"load_coordinates",
]
# Path to the VOIs
_vois_path = Path(__file__).parent / "VOIs"

View file

@ -35,6 +35,16 @@ from .utils import closest_resolution
if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = [
"compute_brain_mask",
"register_mask",
"list_masks",
"get_mask",
"load_mask",
]
# Path to the masks
_masks_path = Path(__file__).parent / "masks"

View file

@ -30,6 +30,15 @@ if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = [
"register_parcellation",
"list_parcellations",
"get_parcellation",
"load_parcellation",
"merge_parcellations",
]
# A dictionary containing all supported parcellations and their respective
# valid parameters.

View file

@ -15,6 +15,9 @@ from ..utils import logger, raise_error
from .utils import closest_resolution
__all__ = ["get_xfm", "get_template"]
def get_xfm(
src: str, dst: str, xfms_dir: Union[str, Path, None] = None
) -> Path: # pragma: no cover

View file

@ -7,6 +7,9 @@ import numpy as np
from ..utils.logging import logger
__all__ = ["closest_resolution"]
def closest_resolution(
resolution: Optional[Union[float, int]],
valid_resolution: Union[List[float], List[int], np.ndarray],

View file

@ -16,3 +16,18 @@ from .aomic import DataladAOMICID1000, DataladAOMICPIOP1, DataladAOMICPIOP2
from .hcp1200 import HCP1200, DataladHCP1200
from .multiple import MultipleDataGrabber
from .dmcc13_benchmark import DMCC13Benchmark
__all__ = [
"BaseDataGrabber",
"DataladDataGrabber",
"PatternDataGrabber",
"PatternDataladDataGrabber",
"DataladAOMICID1000",
"DataladAOMICPIOP1",
"DataladAOMICPIOP2",
"HCP1200",
"DataladHCP1200",
"MultipleDataGrabber",
"DMCC13Benchmark",
]

View file

@ -7,3 +7,6 @@
from .id1000 import DataladAOMICID1000
from .piop1 import DataladAOMICPIOP1
from .piop2 import DataladAOMICPIOP2
__all__ = ["DataladAOMICID1000", "DataladAOMICPIOP1", "DataladAOMICPIOP2"]

View file

@ -14,6 +14,9 @@ from ...api.decorators import register_datagrabber
from ..pattern_datalad import PatternDataladDataGrabber
__all__ = ["DataladAOMICID1000"]
@register_datagrabber
class DataladAOMICID1000(PatternDataladDataGrabber):
"""Concrete implementation for datalad-based data fetching of AOMIC ID1000.

View file

@ -16,6 +16,9 @@ from ...utils import raise_error
from ..pattern_datalad import PatternDataladDataGrabber
__all__ = ["DataladAOMICPIOP1"]
@register_datagrabber
class DataladAOMICPIOP1(PatternDataladDataGrabber):
"""Concrete implementation for pattern-based data fetching of AOMIC PIOP1.

View file

@ -16,6 +16,9 @@ from ...utils import raise_error
from ..pattern_datalad import PatternDataladDataGrabber
__all__ = ["DataladAOMICPIOP2"]
@register_datagrabber
class DataladAOMICPIOP2(PatternDataladDataGrabber):
"""Concrete implementation for pattern-based data fetching of AOMIC PIOP2.

View file

@ -14,6 +14,9 @@ from ..utils import logger, raise_error
from .utils import validate_types
__all__ = ["BaseDataGrabber"]
class BaseDataGrabber(ABC, UpdateMetaMixin):
"""Abstract base class for DataGrabber.

View file

@ -21,6 +21,9 @@ from ..utils import logger, raise_error, warn_with_log
from .base import BaseDataGrabber
__all__ = ["DataladDataGrabber"]
class DataladDataGrabber(BaseDataGrabber):
"""Abstract base class for datalad-based data fetching.

View file

@ -5,3 +5,6 @@
from .hcp1200 import HCP1200
from .datalad_hcp1200 import DataladHCP1200
__all__ = ["HCP1200", "DataladHCP1200"]

View file

@ -14,6 +14,9 @@ from ...api.decorators import register_datagrabber
from .hcp1200 import HCP1200
__all__ = ["DataladHCP1200"]
@register_datagrabber
class DataladHCP1200(DataladDataGrabber, HCP1200):
"""Concrete implementation for datalad-based data fetching of HCP1200.

View file

@ -14,6 +14,9 @@ from ..pattern import PatternDataGrabber
from ..utils import raise_error
__all__ = ["HCP1200"]
@register_datagrabber
class HCP1200(PatternDataGrabber):
"""Concrete implementation for pattern-based data fetching of HCP1200.

View file

@ -11,6 +11,9 @@ from ..utils import raise_error
from .base import BaseDataGrabber
__all__ = ["MultipleDataGrabber"]
class MultipleDataGrabber(BaseDataGrabber):
"""Concrete implementation for multi sourced data fetching.

View file

@ -18,6 +18,9 @@ from .base import BaseDataGrabber
from .utils import validate_patterns, validate_replacements
__all__ = ["PatternDataGrabber"]
# Accepted formats for confounds specification
_CONFOUNDS_FORMATS = ("fmriprep", "adhoc")

View file

@ -12,6 +12,9 @@ from .datalad_base import DataladDataGrabber
from .pattern import PatternDataGrabber
__all__ = ["PatternDataladDataGrabber"]
@register_datagrabber
class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
"""Concrete implementation for pattern and datalad based data fetching.

View file

@ -9,6 +9,9 @@ from typing import Dict, List
from ..utils import logger, raise_error
__all__ = ["validate_types", "validate_replacements", "validate_patterns"]
# Define schema for pattern-based datagrabber's patterns
PATTERNS_SCHEMA = {
"T1w": {

View file

@ -6,3 +6,6 @@
# License: AGPL
from .default import DefaultDataReader
__all__ = ["DefaultDataReader"]

View file

@ -15,6 +15,9 @@ from ..pipeline import PipelineStepMixin, UpdateMetaMixin
from ..utils.logging import logger, warn_with_log
__all__ = ["DefaultDataReader"]
# Map each file extension to a type
_extensions = {
".nii": "NIFTI",

View file

@ -24,3 +24,24 @@ from .temporal_snr import (
TemporalSNRSpheres,
)
from .brainprint import BrainPrint
__all__ = [
"BaseMarker",
"MarkerCollection",
"RSSETSMarker",
"ParcelAggregation",
"SphereAggregation",
"FunctionalConnectivityParcels",
"FunctionalConnectivitySpheres",
"CrossParcellationFC",
"EdgeCentricFCParcels",
"EdgeCentricFCSpheres",
"ReHoParcels",
"ReHoSpheres",
"ALFFParcels",
"ALFFSpheres",
"TemporalSNRParcels",
"TemporalSNRSpheres",
"BrainPrint",
]

View file

@ -15,16 +15,22 @@ if TYPE_CHECKING:
from junifer.storage import BaseFeatureStorage
__all__ = ["BaseMarker"]
class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
"""Abstract base class for all markers.
For every interface that is required, one needs to provide a concrete
implementation of this abstract class.
Parameters
----------
on : str or list of str
The kind of data to apply the marker to. By default, will work on all
available data.
on : str or list of str or None, optional
The data type to apply the marker on. If None,
will work on all available data types (default None).
name : str, optional
The name of the marker. By default, it will use the class name as the
The name of the marker. If None, will use the class name as the
name of the marker (default None).
Raises
@ -192,17 +198,25 @@ class BaseMarker(ABC, PipelineStepMixin, UpdateMetaMixin):
for type_ in self._on:
if type_ in input.keys():
logger.info(f"Computing {type_}")
# Get data dict for data type
t_input = input[type_]
# Pass the other data types as extra input, removing
# the current type
extra_input = input.copy()
extra_input.pop(type_)
logger.debug(
f"Extra data type for feature extraction: "
f"{extra_input.keys()}"
)
# Copy metadata
t_meta = t_input["meta"].copy()
t_meta["type"] = type_
# Compute marker
t_out = self.compute(input=t_input, extra_input=extra_input)
t_out["meta"] = t_meta
# Update metadata for step
self.update_meta(t_out, "marker")
# Check storage
if storage is not None:
logger.info(f"Storing in {storage}")
self.store(type_=type_, out=t_out, storage=storage)

View file

@ -43,6 +43,9 @@ if TYPE_CHECKING:
from junifer.storage import BaseFeatureStorage
__all__ = ["BrainPrint"]
@register_marker
class BrainPrint(BaseMarker):
"""Class for BrainPrint.

View file

@ -19,6 +19,9 @@ if TYPE_CHECKING:
from junifer.datagrabber import BaseDataGrabber
__all__ = ["MarkerCollection"]
class MarkerCollection:
"""Class for marker collection.

View file

@ -25,3 +25,13 @@ else:
from .weighted_perm_entropy import WeightedPermEntropy
from .sample_entropy import SampleEntropy
from .multiscale_entropy_auc import MultiscaleEntropyAUC
__all__ = [
"HurstExponent",
"RangeEntropy",
"RangeEntropyAUC",
"PermEntropy",
"WeightedPermEntropy",
"SampleEntropy",
"MultiscaleEntropyAUC",
]

View file

@ -24,6 +24,9 @@ if TYPE_CHECKING:
import numpy as np
__all__ = ["ComplexityBase"]
class ComplexityBase(BaseMarker):
"""Base class for complexity computation.

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["HurstExponent"]
@register_marker
class HurstExponent(ComplexityBase):
"""Class for Hurst exponent of a time series.

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["MultiscaleEntropyAUC"]
@register_marker
class MultiscaleEntropyAUC(ComplexityBase):
"""Class for AUC of multiscale entropy of a time series.

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["PermEntropy"]
@register_marker
class PermEntropy(ComplexityBase):
"""Class for permutation entropy of a time series.

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["RangeEntropy"]
@register_marker
class RangeEntropy(ComplexityBase):
"""Class for range entropy of a time series.

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["RangeEntropyAUC"]
@register_marker
class RangeEntropyAUC(ComplexityBase):
"""Class for AUC of range entropy values of a time series over r = 0 to 1.

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["SampleEntropy"]
@register_marker
class SampleEntropy(ComplexityBase):
"""Class for sample entropy of a time series.

View file

@ -14,6 +14,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import HurstExponent # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -24,6 +25,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test HurstExponent compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -45,6 +49,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test HurstExponent store().

View file

@ -13,6 +13,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import MultiscaleEntropyAUC # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -23,6 +24,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test MultiscaleEntropyAUC compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -44,6 +48,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test MultiscaleEntropyAUC store().

View file

@ -13,6 +13,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import PermEntropy # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -23,6 +24,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test PermEntropy compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -44,6 +48,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test PermEntropy store().

View file

@ -14,6 +14,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import RangeEntropy # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -24,6 +25,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test RangeEntropy compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -45,6 +49,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test RangeEntropy store().

View file

@ -14,6 +14,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import RangeEntropyAUC # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -24,6 +25,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test RangeEntropyAUC compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -45,6 +49,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test RangeEntropyAUC store().

View file

@ -13,6 +13,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import SampleEntropy # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -23,6 +24,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test SampleEntropy compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -44,6 +48,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test SampleEntropy store().

View file

@ -13,6 +13,7 @@ pytest.importorskip("neurokit2")
from junifer.datareader import DefaultDataReader # noqa: E402
from junifer.markers.complexity import WeightedPermEntropy # noqa: E402
from junifer.pipeline.utils import _check_ants # noqa: E402
from junifer.storage import SQLiteFeatureStorage # noqa: E402
from junifer.testing.datagrabbers import ( # noqa: E402
SPMAuditoryTestingDataGrabber,
@ -23,6 +24,9 @@ from junifer.testing.datagrabbers import ( # noqa: E402
PARCELLATION = "Schaefer100x17"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_compute() -> None:
"""Test WeightedPermEntropy compute()."""
with SPMAuditoryTestingDataGrabber() as dg:
@ -44,6 +48,9 @@ def test_get_output_type() -> None:
assert marker.get_output_type("BOLD") == "vector"
@pytest.mark.skipif(
_check_ants() is False, reason="requires ANTs to be in PATH"
)
def test_store(tmp_path: Path) -> None:
"""Test WeightedPermEntropy store().

View file

@ -14,6 +14,9 @@ from ...utils import logger, warn_with_log
from .complexity_base import ComplexityBase
__all__ = ["WeightedPermEntropy"]
@register_marker
class WeightedPermEntropy(ComplexityBase):
"""Class for weighted permutation entropy of a time series.

View file

@ -17,6 +17,9 @@ from .parcel_aggregation import ParcelAggregation
from .utils import _ets
__all__ = ["RSSETSMarker"]
@register_marker
class RSSETSMarker(BaseMarker):
"""Class for root sum of squares of edgewise timeseries.

View file

@ -5,3 +5,6 @@
from .falff_parcels import ALFFParcels
from .falff_spheres import ALFFSpheres
__all__ = ["ALFFParcels", "ALFFSpheres"]

View file

@ -26,6 +26,9 @@ if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = ["AFNIALFF"]
@singleton
class AFNIALFF:
"""Class for computing ALFF using AFNI.

View file

@ -27,6 +27,9 @@ if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = ["JuniferALFF"]
@singleton
class JuniferALFF:
"""Class for computing ALFF using junifer.

View file

@ -29,6 +29,9 @@ if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = ["ALFFBase"]
class ALFFBase(BaseMarker):
"""Base class for (fractional) Amplitude Low Frequency Fluctuation.

View file

@ -14,6 +14,9 @@ from ..parcel_aggregation import ParcelAggregation
from .falff_base import ALFFBase
__all__ = ["ALFFParcels"]
@register_marker
class ALFFParcels(ALFFBase):
"""Class for ALFF / fALFF on parcels.

View file

@ -14,6 +14,9 @@ from ..sphere_aggregation import SphereAggregation
from .falff_base import ALFFBase
__all__ = ["ALFFSpheres"]
@register_marker
class ALFFSpheres(ALFFBase):
"""Class for computing ALFF / fALFF on spheres.

View file

@ -8,3 +8,12 @@ from .functional_connectivity_spheres import FunctionalConnectivitySpheres
from .crossparcellation_functional_connectivity import CrossParcellationFC
from .edge_functional_connectivity_parcels import EdgeCentricFCParcels
from .edge_functional_connectivity_spheres import EdgeCentricFCSpheres
__all__ = [
"FunctionalConnectivityParcels",
"FunctionalConnectivitySpheres",
"CrossParcellationFC",
"EdgeCentricFCParcels",
"EdgeCentricFCSpheres",
]

View file

@ -15,6 +15,9 @@ from ..parcel_aggregation import ParcelAggregation
from ..utils import _correlate_dataframes
__all__ = ["CrossParcellationFC"]
@register_marker
class CrossParcellationFC(BaseMarker):
"""Class for calculating parcel-wise correlations with 2 parcellations.

View file

@ -12,6 +12,9 @@ from ..utils import _ets
from .functional_connectivity_base import FunctionalConnectivityBase
__all__ = ["EdgeCentricFCParcels"]
@register_marker
class EdgeCentricFCParcels(FunctionalConnectivityBase):
"""Class for edge-centric FC using parcellations.

View file

@ -12,6 +12,9 @@ from ..utils import _ets, raise_error
from .functional_connectivity_base import FunctionalConnectivityBase
__all__ = ["EdgeCentricFCSpheres"]
@register_marker
class EdgeCentricFCSpheres(FunctionalConnectivityBase):
"""Class for edge-centric FC using coordinates (spheres).

View file

@ -14,6 +14,9 @@ from ...utils import raise_error
from ..base import BaseMarker
__all__ = ["FunctionalConnectivityBase"]
class FunctionalConnectivityBase(BaseMarker):
"""Abstract base class for functional connectivity markers.

View file

@ -12,6 +12,9 @@ from ..parcel_aggregation import ParcelAggregation
from .functional_connectivity_base import FunctionalConnectivityBase
__all__ = ["FunctionalConnectivityParcels"]
@register_marker
class FunctionalConnectivityParcels(FunctionalConnectivityBase):
"""Class for functional connectivity using parcellations.

View file

@ -13,6 +13,9 @@ from ..utils import raise_error
from .functional_connectivity_base import FunctionalConnectivityBase
__all__ = ["FunctionalConnectivitySpheres"]
@register_marker
class FunctionalConnectivitySpheres(FunctionalConnectivityBase):
"""Class for functional connectivity using coordinates (spheres).

View file

@ -17,6 +17,9 @@ from ..utils import logger, raise_error, warn_with_log
from .base import BaseMarker
__all__ = ["ParcelAggregation"]
@register_marker
class ParcelAggregation(BaseMarker):
"""Class for parcel aggregation.

View file

@ -5,3 +5,6 @@
from .reho_parcels import ReHoParcels
from .reho_spheres import ReHoSpheres
__all__ = ["ReHoParcels", "ReHoSpheres"]

View file

@ -26,6 +26,9 @@ if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = ["AFNIReHo"]
@singleton
class AFNIReHo:
"""Class for computing ReHo using AFNI.

View file

@ -28,6 +28,9 @@ if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = ["JuniferReHo"]
@singleton
class JuniferReHo:
"""Class for computing ReHo using junifer.

View file

@ -26,6 +26,8 @@ from ._junifer_reho import JuniferReHo
if TYPE_CHECKING:
from nibabel import Nifti1Image
__all__ = ["ReHoBase"]
class ReHoBase(BaseMarker):
"""Base class for regional homogeneity computation.

View file

@ -14,6 +14,9 @@ from ..parcel_aggregation import ParcelAggregation
from .reho_base import ReHoBase
__all__ = ["ReHoParcels"]
@register_marker
class ReHoParcels(ReHoBase):
"""Class for regional homogeneity on parcels.

View file

@ -14,6 +14,9 @@ from ..sphere_aggregation import SphereAggregation
from .reho_base import ReHoBase
__all__ = ["ReHoSpheres"]
@register_marker
class ReHoSpheres(ReHoBase):
"""Class for regional homogeneity on spheres.

View file

@ -14,6 +14,9 @@ from ..utils import logger, raise_error, warn_with_log
from .base import BaseMarker
__all__ = ["SphereAggregation"]
@register_marker
class SphereAggregation(BaseMarker):
"""Class for sphere aggregation.

View file

@ -5,3 +5,6 @@
from .temporal_snr_parcels import TemporalSNRParcels
from .temporal_snr_spheres import TemporalSNRSpheres
__all__ = ["TemporalSNRParcels", "TemporalSNRSpheres"]

View file

@ -13,6 +13,9 @@ from ...utils import raise_error
from ..base import BaseMarker
__all__ = ["TemporalSNRBase"]
class TemporalSNRBase(BaseMarker):
"""Abstract base class for temporal SNR markers.

View file

@ -10,6 +10,9 @@ from ..parcel_aggregation import ParcelAggregation
from .temporal_snr_base import TemporalSNRBase
__all__ = ["TemporalSNRParcels"]
@register_marker
class TemporalSNRParcels(TemporalSNRBase):
"""Class for temporal signal-to-noise ratio using parcellations.

View file

@ -11,6 +11,9 @@ from ..utils import raise_error
from .temporal_snr_base import TemporalSNRBase
__all__ = ["TemporalSNRSpheres"]
@register_marker
class TemporalSNRSpheres(TemporalSNRBase):
"""Class for temporal signal-to-noise ratio using coordinates (spheres).

View file

@ -4,3 +4,6 @@
# License: AGPL
from .read_transform import read_transform
__all__ = ["read_transform"]

View file

@ -15,6 +15,9 @@ if TYPE_CHECKING:
from junifer.storage import BaseFeatureStorage
__all__ = ["read_transform"]
def read_transform(
storage: Type["BaseFeatureStorage"],
transform: str,

View file

@ -7,3 +7,11 @@ from . import registry
from .pipeline_step_mixin import PipelineStepMixin
from .update_meta_mixin import UpdateMetaMixin
from .workdir_manager import WorkDirManager
__all__ = [
"registry",
"PipelineStepMixin",
"UpdateMetaMixin",
"WorkDirManager",
]

View file

@ -17,6 +17,9 @@ from ..utils import raise_error
from .utils import check_ext_dependencies
__all__ = ["PipelineStepMixin"]
class PipelineStepMixin:
"""Mixin class for a pipeline step."""

View file

@ -16,6 +16,9 @@ if TYPE_CHECKING:
from .pipeline_step_mixin import PipelineStepMixin
__all__ = ["register", "get_step_names", "get_class", "build"]
# Define valid steps for operation
_VALID_STEPS: List[str] = [
"datagrabber",

View file

@ -6,6 +6,9 @@
from typing import Any, Dict, Type
__all__ = ["singleton"]
def singleton(cls: Type) -> Type:
"""Make a class singleton.

Some files were not shown because too many files have changed in this diff Show more