Skip to content

Commit 45655b8

Browse files
committed
Merge tag '24.1.0'
24.1.0 (October 02, 2024) This new minor release includes a few bug fixes, such as excluding MCRIBS from surface reconstruction without a precomputed segmentation and ensuring generated derivatives are not masked, as well as improvements to reporting. * ENH: Add boilerplate, errors to report (#403) * ENH: Add age to session report (#402) * ENH: Improvements to age parsing (#395, #398) * FIX: MCRIBS auto surface reconstruction logic (#399) * FIX: Do not force masking of anatomicals when using `--derivatives` (#400) * MAINT: Revisit warnings filter (#396) * MAINT: Automate testing with tox (#404) * MAINT: Port over parser arguments and tests from fmriprep (#401)
2 parents 915fb6f + 27c0a55 commit 45655b8

File tree

11 files changed

+246
-116
lines changed

11 files changed

+246
-116
lines changed

.pre-commit-config.yaml

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
exclude: ".*/data/.*"
22
repos:
3-
- repo: https://github.com/pre-commit/pre-commit-hooks
4-
rev: v4.4.0
5-
hooks:
6-
- id: trailing-whitespace
7-
exclude: '.*\.svg'
8-
- id: end-of-file-fixer
9-
exclude: '.*\.svg'
10-
- id: check-yaml
11-
- id: check-json
12-
- id: check-toml
13-
- id: check-added-large-files
14-
- repo: https://github.com/astral-sh/ruff-pre-commit
15-
rev: v0.6.5
16-
hooks:
17-
- id: ruff
18-
args: [ --fix ]
19-
- id: ruff-format
3+
- repo: https://github.com/pre-commit/pre-commit-hooks
4+
rev: v4.4.0
5+
hooks:
6+
- id: trailing-whitespace
7+
exclude: '.*\.svg'
8+
- id: end-of-file-fixer
9+
exclude: '.*\.svg'
10+
- id: check-yaml
11+
- id: check-json
12+
- id: check-toml
13+
- id: check-added-large-files
14+
- repo: https://github.com/astral-sh/ruff-pre-commit
15+
rev: v0.6.5
16+
hooks:
17+
- id: ruff
18+
args: [--fix]
19+
- id: ruff-format
20+
- repo: https://github.com/codespell-project/codespell
21+
rev: v2.3.0
22+
hooks:
23+
- id: codespell
24+
additional_dependencies:
25+
- tomli

CHANGES.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
24.1.0 (October 02, 2024)
2+
=========================
3+
This new minor release includes a few bug fixes, such as excluding MCRIBS from surface reconstruction without a precomputed segmentation and ensuring generated derivatives are not masked, as well as improvements to reporting.
4+
5+
### Enhancements
6+
* ENH: Add boilerplate, errors to report (#403)
7+
* ENH: Add age to session report (#402)
8+
* ENH: Improvements to age parsing (#395, #398)
9+
10+
### Bug Fixes
11+
* FIX: MCRIBS auto surface reconstruction logic (#399)
12+
* FIX: Do not force masking of anatomicals when using `--derivatives` (#400)
13+
14+
### Internals / Maintenance
15+
* MAINT: Revisit warnings filter (#396)
16+
* MAINT: Automate testing with tox (#404)
17+
* MAINT: Port over parser arguments and tests from fmriprep (#401)
18+
19+
120
24.0.1 (August 31, 2024)
221
========================
322
A patch release with a fix for the BOLD T2\* workflow. The command line argument `--me-t2s-fit-method` was added for finer control when processing multi-echo datasets.

nibabies/conftest.py

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,44 +2,36 @@
22

33
import json
44
from pathlib import Path
5-
from tempfile import TemporaryDirectory
5+
from shutil import copytree
66

77
import nibabel as nb
88
import numpy as np
99
import pytest
1010

1111
from nibabies.data import load as load_data
1212

13-
FILES = (
14-
'functional.nii',
15-
'anatomical.nii',
16-
'func.dlabel.nii',
17-
'func.dtseries.nii',
18-
'epi.nii',
19-
'T1w.nii',
20-
'func_to_struct.mat',
21-
'atlas.nii',
22-
'label_list.txt',
23-
'sub-01_run-01_echo-1_bold.nii.gz',
24-
'sub-01_run-01_echo-2_bold.nii.gz',
25-
'sub-01_run-01_echo-3_bold.nii.gz',
26-
)
27-
28-
29-
@pytest.fixture(scope='package')
30-
def data_dir():
31-
with TemporaryDirectory() as tmpdir:
32-
tmp_path = Path(tmpdir)
33-
for fname in FILES:
34-
Path.touch(tmp_path / fname)
35-
yield tmp_path
13+
try:
14+
from importlib.resources import files as ir_files
15+
except ImportError: # PY<3.9
16+
from importlib_resources import files as ir_files
17+
18+
19+
def copytree_or_skip(source, target):
20+
data_dir = ir_files('nibabies') / source
21+
if not data_dir.exists():
22+
pytest.skip(f'Cannot chdir into {data_dir!r}. Probably in a zipped distribution.')
23+
24+
try:
25+
copytree(data_dir, target / data_dir.name)
26+
except Exception: # noqa: BLE001
27+
pytest.skip(f'Cannot copy {data_dir!r} into {target / data_dir.name}. Probably in a zip.')
3628

3729

3830
@pytest.fixture(autouse=True)
39-
def _populate_namespace(doctest_namespace, data_dir):
40-
doctest_namespace['data_dir'] = data_dir
41-
doctest_namespace['test_data'] = load_data.cached('../tests/data')
42-
doctest_namespace['Path'] = Path
31+
def _populate_namespace(doctest_namespace, tmp_path):
32+
doctest_namespace['copytree_or_skip'] = copytree_or_skip
33+
doctest_namespace['testdir'] = tmp_path
34+
doctest_namespace['datadir'] = load_data()
4335

4436

4537
@pytest.fixture

nibabies/data/boilerplate.bib

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,29 @@ @article{mcribs
391391
title = {Parcellation of the neonatal cortex using Surface-based Melbourne Children's Regional Infant Brain atlases (M-{CRIB}-S)},
392392
journal = {Scientific Reports}
393393
}
394+
395+
@article{patriat_improved_2017,
396+
title = {An improved model of motion-related signal changes in {fMRI}},
397+
volume = {144, Part A},
398+
issn = {1053-8119},
399+
url = {https://www.sciencedirect.com/science/article/pii/S1053811916304360},
400+
doi = {10.1016/j.neuroimage.2016.08.051},
401+
abstract = {Head motion is a significant source of noise in the estimation of functional connectivity from resting-state functional MRI (rs-fMRI). Current strategies to reduce this noise include image realignment, censoring time points corrupted by motion, and including motion realignment parameters and their derivatives as additional nuisance regressors in the general linear model. However, this nuisance regression approach assumes that the motion-induced signal changes are linearly related to the estimated realignment parameters, which is not always the case. In this study we develop an improved model of motion-related signal changes, where nuisance regressors are formed by first rotating and translating a single brain volume according to the estimated motion, re-registering the data, and then performing a principal components analysis (PCA) on the resultant time series of both moved and re-registered data. We show that these “Motion Simulated (MotSim)” regressors account for significantly greater fraction of variance, result in higher temporal signal-to-noise, and lead to functional connectivity estimates that are less affected by motion compared to the most common current approach of using the realignment parameters and their derivatives as nuisance regressors. This improvement should lead to more accurate estimates of functional connectivity, particularly in populations where motion is prevalent, such as patients and young children.},
402+
urldate = {2017-01-18},
403+
journal = {NeuroImage},
404+
author = {Patriat, Rémi and Reynolds, Richard C. and Birn, Rasmus M.},
405+
month = jan,
406+
year = {2017},
407+
keywords = {Motion, Correction, Methods, Rs-fMRI},
408+
pages = {74--82},
409+
}
410+
411+
@article{templateflow,
412+
author = {Ciric, R. and Thompson, William H. and Lorenz, R. and Goncalves, M. and MacNicol, E. and Markiewicz, C. J. and Halchenko, Y. O. and Ghosh, S. S. and Gorgolewski, K. J. and Poldrack, R. A. and Esteban, O.},
413+
title = {{TemplateFlow}: {FAIR}-sharing of multi-scale, multi-species brain models},
414+
volume = {19},
415+
pages = {1568--1571},
416+
year = {2022},
417+
doi = {10.1038/s41592-022-01681-2},
418+
journal = {Nature Methods}
419+
}

nibabies/data/sub-01_run-01_echo-1_bold.nii.gz

Whitespace-only changes.

nibabies/data/sub-01_run-01_echo-2_bold.nii.gz

Whitespace-only changes.

nibabies/data/sub-01_run-01_echo-3_bold.nii.gz

Whitespace-only changes.

nibabies/interfaces/conftest.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from pathlib import Path
2+
from shutil import copytree
3+
from tempfile import TemporaryDirectory
4+
5+
import pytest
6+
7+
try:
8+
from contextlib import chdir as _chdir
9+
except ImportError: # PY310
10+
import os
11+
from contextlib import contextmanager
12+
13+
@contextmanager # type: ignore
14+
def _chdir(path):
15+
cwd = os.getcwd()
16+
os.chdir(path)
17+
try:
18+
yield
19+
finally:
20+
os.chdir(cwd)
21+
22+
23+
DATA_FILES = (
24+
'functional.nii',
25+
'anatomical.nii',
26+
'func.dlabel.nii',
27+
'func.dtseries.nii',
28+
'epi.nii',
29+
'T1w.nii',
30+
'func_to_struct.mat',
31+
'atlas.nii',
32+
'label_list.txt',
33+
'sub-01_run-01_echo-1_bold.nii.gz',
34+
'sub-01_run-01_echo-2_bold.nii.gz',
35+
'sub-01_run-01_echo-3_bold.nii.gz',
36+
)
37+
38+
39+
@pytest.fixture(scope='package')
40+
def data_dir():
41+
with TemporaryDirectory() as tmpdir:
42+
tmp_path = Path(tmpdir)
43+
for fname in DATA_FILES:
44+
Path.touch(tmp_path / fname)
45+
yield tmp_path
46+
47+
48+
@pytest.fixture(autouse=True)
49+
def _docdir(data_dir, request, tmp_path):
50+
# Trigger ONLY for the doctests.
51+
doctest_plugin = request.config.pluginmanager.getplugin('doctest')
52+
if isinstance(request.node, doctest_plugin.DoctestItem):
53+
copytree(data_dir, tmp_path, dirs_exist_ok=True)
54+
55+
# Chdir only for the duration of the test.
56+
with _chdir(tmp_path):
57+
yield
58+
59+
else:
60+
# For normal tests, we have to yield, since this is a yield-fixture.
61+
yield

nibabies/interfaces/workbench.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,16 @@ class CiftiCreateDenseFromTemplate(WBCommand):
164164
165165
>>> from nibabies.interfaces import workbench as wb
166166
>>> frmtpl = wb.CiftiCreateDenseFromTemplate()
167-
>>> frmtpl.inputs.in_file = data_dir / "func.dtseries.nii"
167+
>>> frmtpl.inputs.in_file = testdir / "func.dtseries.nii"
168168
>>> frmtpl.inputs.series = True
169169
>>> frmtpl.inputs.series_step = 0.8
170170
>>> frmtpl.inputs.series_start = 0
171171
>>> frmtpl.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
172172
'wb_command -cifti-create-dense-from-template .../func.dtseries.nii \
173173
template_func.dtseries.nii -series 0.8 0.0'
174174
175-
>>> frmtpl.inputs.volume = [("OTHER", data_dir / 'functional.nii', True), \
176-
("PUTAMEN_LEFT", data_dir / 'functional.nii')]
175+
>>> frmtpl.inputs.volume = [("OTHER", testdir / 'functional.nii', True), \
176+
("PUTAMEN_LEFT", testdir / 'functional.nii')]
177177
>>> frmtpl.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
178178
'wb_command -cifti-create-dense-from-template .../func.dtseries.nii \
179179
template_func.dtseries.nii -series 0.8 0.0 \
@@ -330,8 +330,8 @@ class CiftiCreateDenseTimeseries(WBCommand):
330330
331331
>>> from nibabies.interfaces.workbench import CiftiCreateDenseTimeseries
332332
>>> createdts = CiftiCreateDenseTimeseries()
333-
>>> createdts.inputs.volume_data = data_dir /'functional.nii'
334-
>>> createdts.inputs.volume_structure_labels = data_dir / 'atlas.nii'
333+
>>> createdts.inputs.volume_data = testdir /'functional.nii'
334+
>>> createdts.inputs.volume_structure_labels = testdir / 'atlas.nii'
335335
>>> createdts.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
336336
'wb_command -cifti-create-dense-timeseries out.dtseries.nii \
337337
-volume .../functional.nii .../atlas.nii'
@@ -467,8 +467,8 @@ class CiftiCreateLabel(WBCommand):
467467
468468
>>> from nibabies.interfaces import workbench as wb
469469
>>> lab = wb.CiftiCreateLabel()
470-
>>> lab.inputs.volume_label = data_dir / "functional.nii"
471-
>>> lab.inputs.structure_label_volume = data_dir / "functional.nii"
470+
>>> lab.inputs.volume_label = testdir / "functional.nii"
471+
>>> lab.inputs.structure_label_volume = testdir / "functional.nii"
472472
>>> lab.cmdline # doctest: +ELLIPSIS
473473
'wb_command -cifti-create-label out.dlabel.nii -volume .../functional.nii .../functional.nii'
474474
"""
@@ -940,9 +940,9 @@ class CiftiResample(WBCommand):
940940
941941
>>> from nibabies.interfaces import workbench as wb
942942
>>> res = wb.CiftiResample()
943-
>>> res.inputs.in_file = data_dir / "func.dtseries.nii"
943+
>>> res.inputs.in_file = testdir / "func.dtseries.nii"
944944
>>> res.inputs.direction = "COLUMN"
945-
>>> res.inputs.template = data_dir / "func.dlabel.nii"
945+
>>> res.inputs.template = testdir / "func.dlabel.nii"
946946
>>> res.inputs.template_direction = "COLUMN"
947947
>>> res.inputs.surface_method = "ADAP_BARY_AREA"
948948
>>> res.inputs.volume_method = "CUBIC"
@@ -1051,7 +1051,7 @@ class CiftiSeparate(WBCommand):
10511051
dimension, columns for .dtseries.
10521052
10531053
>>> separate = CiftiSeparate()
1054-
>>> separate.inputs.in_file = data_dir / "func.dtseries.nii"
1054+
>>> separate.inputs.in_file = testdir / "func.dtseries.nii"
10551055
>>> separate.inputs.direction = "COLUMN"
10561056
>>> separate.inputs.volume_all_file = "volume_all.nii.gz"
10571057
>>> separate.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
@@ -1216,10 +1216,10 @@ class VolumeAffineResample(WBCommand):
12161216
12171217
>>> from nibabies.interfaces.workbench import VolumeAffineResample
12181218
>>> resample = VolumeAffineResample()
1219-
>>> resample.inputs.in_file = data_dir /'functional.nii'
1220-
>>> resample.inputs.volume_space = data_dir /'anatomical.nii'
1219+
>>> resample.inputs.in_file = testdir /'functional.nii'
1220+
>>> resample.inputs.volume_space = testdir /'anatomical.nii'
12211221
>>> resample.inputs.method = 'CUBIC'
1222-
>>> resample.inputs.affine = data_dir / 'func_to_struct.mat'
1222+
>>> resample.inputs.affine = testdir / 'func_to_struct.mat'
12231223
>>> resample.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
12241224
'wb_command -volume-resample .../functional.nii .../anatomical.nii CUBIC \
12251225
resampled_functional.nii.gz -affine .../func_to_struct.mat'
@@ -1237,8 +1237,8 @@ class VolumeAffineResample(WBCommand):
12371237
However, if other volumes were used to calculate the affine, they can
12381238
be provided:
12391239
1240-
>>> resample.inputs.flirt_source_volume = data_dir / 'epi.nii'
1241-
>>> resample.inputs.flirt_target_volume = data_dir /'T1w.nii'
1240+
>>> resample.inputs.flirt_source_volume = testdir / 'epi.nii'
1241+
>>> resample.inputs.flirt_target_volume = testdir /'T1w.nii'
12421242
>>> resample.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
12431243
'wb_command -volume-resample .../functional.nii .../anatomical.nii CUBIC \
12441244
resampled_functional.nii.gz -affine .../func_to_struct.mat \
@@ -1297,7 +1297,7 @@ class VolumeAllLabelsToROIs(WBCommand):
12971297
12981298
>>> from nibabies.interfaces.workbench import VolumeAllLabelsToROIs
12991299
>>> rois = VolumeAllLabelsToROIs()
1300-
>>> rois.inputs.in_file = data_dir / 'atlas.nii'
1300+
>>> rois.inputs.in_file = testdir / 'atlas.nii'
13011301
>>> rois.inputs.label_map = 1
13021302
>>> rois.cmdline # doctest: +ELLIPSIS
13031303
'wb_command -volume-all-labels-to-rois .../atlas.nii 1 atlas_rois.nii.gz'
@@ -1346,7 +1346,7 @@ class VolumeLabelExportTable(WBCommand):
13461346
13471347
>>> from nibabies.interfaces.workbench import VolumeLabelExportTable
13481348
>>> label_export = VolumeLabelExportTable()
1349-
>>> label_export.inputs.in_file = data_dir / 'atlas.nii'
1349+
>>> label_export.inputs.in_file = testdir / 'atlas.nii'
13501350
>>> label_export.inputs.label_map = 1
13511351
>>> label_export.cmdline # doctest: +ELLIPSIS
13521352
'wb_command -volume-label-export-table .../atlas.nii 1 atlas_labels.txt'
@@ -1434,8 +1434,8 @@ class VolumeLabelImport(WBCommand):
14341434
14351435
>>> from nibabies.interfaces.workbench import VolumeLabelImport
14361436
>>> label_import = VolumeLabelImport()
1437-
>>> label_import.inputs.in_file = data_dir / 'atlas.nii'
1438-
>>> label_import.inputs.label_list_file = data_dir / 'label_list.txt'
1437+
>>> label_import.inputs.in_file = testdir / 'atlas.nii'
1438+
>>> label_import.inputs.label_list_file = testdir / 'label_list.txt'
14391439
>>> label_import.cmdline # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE
14401440
'wb_command -volume-label-import .../atlas.nii .../label_list.txt \
14411441
atlas_labels.nii.gz'

nibabies/workflows/bold/alignment.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,11 @@ def parse_roi_labels(label_file: str):
321321
322322
Return a list of structure names and label keys.
323323
324-
>>> structs, ids = parse_roi_labels(test_data / "labelfile.txt")
324+
>>> structs, ids = parse_roi_labels(datadir / "FreeSurferSubcorticalLabelTableLut.txt")
325325
>>> structs
326-
['CEREBELLUM_LEFT', 'THALAMUS_LEFT', 'CAUDATE_LEFT']
326+
['ACCUMBENS_LEFT', 'ACCUMBENS_RIGHT', 'AMYGDALA_LEFT', ...]
327327
>>> ids
328-
[8, 10, 11]
328+
[26, 58, 18, ...]
329329
"""
330330

331331
with open(label_file) as fp:

0 commit comments

Comments
 (0)