Skip to content

Commit bf488e8

Browse files
committed
enh: move signal extraction functions to a better location
1 parent 61834f2 commit bf488e8

File tree

4 files changed

+97
-70
lines changed

4 files changed

+97
-70
lines changed

niworkflows/interfaces/plotting.py

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@
3333
traits,
3434
isdefined,
3535
)
36-
from ..viz.plots import fMRIPlot, compcor_variance_plot, confounds_correlation_plot
36+
from niworkflows.utils.timeseries import _cifti_timeseries, _nifti_timeseries
37+
from niworkflows.viz.plots import (
38+
fMRIPlot,
39+
compcor_variance_plot,
40+
confounds_correlation_plot,
41+
)
3742

3843

3944
class _FMRISummaryInputSpec(BaseInterfaceInputSpec):
@@ -222,65 +227,6 @@ def _run_interface(self, runtime):
222227
return runtime
223228

224229

225-
def _cifti_timeseries(dataset):
226-
"""Extract timeseries from CIFTI2 dataset."""
227-
dataset = nb.load(dataset) if isinstance(dataset, str) else dataset
228-
229-
if dataset.nifti_header.get_intent()[0] != "ConnDenseSeries":
230-
raise ValueError("Not a dense timeseries")
231-
232-
matrix = dataset.header.matrix
233-
labels = {
234-
"CIFTI_STRUCTURE_CORTEX_LEFT": "CtxL",
235-
"CIFTI_STRUCTURE_CORTEX_RIGHT": "CtxR",
236-
"CIFTI_STRUCTURE_CEREBELLUM_LEFT": "CbL",
237-
"CIFTI_STRUCTURE_CEREBELLUM_RIGHT": "CbR",
238-
}
239-
seg = {label: [] for label in list(labels.values()) + ["Other"]}
240-
for bm in matrix.get_index_map(1).brain_models:
241-
label = (
242-
"Other" if bm.brain_structure not in labels else
243-
labels[bm.brain_structure]
244-
)
245-
seg[label] += list(range(
246-
bm.index_offset, bm.index_offset + bm.index_count
247-
))
248-
249-
return dataset.get_fdata(dtype="float32").T, seg
250-
251-
252-
def _nifti_timeseries(
253-
dataset,
254-
segmentation=None,
255-
lut=None,
256-
labels=("Ctx GM", "dGM", "WM+CSF", "Cb")
257-
):
258-
"""Extract timeseries from NIfTI1/2 datasets."""
259-
dataset = nb.load(dataset) if isinstance(dataset, str) else dataset
260-
data = dataset.get_fdata(dtype="float32").reshape((-1, dataset.shape[-1]))
261-
262-
if segmentation is None:
263-
return data, None
264-
265-
segmentation = nb.load(segmentation) if isinstance(segmentation, str) else segmentation
266-
# Map segmentation
267-
if lut is None:
268-
lut = np.zeros((256,), dtype="int")
269-
lut[100:201] = 1 # Ctx GM
270-
lut[30:99] = 2 # dGM
271-
lut[1:11] = 3 # WM+CSF
272-
lut[255] = 4 # Cerebellum
273-
# Apply lookup table
274-
seg = lut[np.asanyarray(segmentation.dataobj, dtype=int)].reshape(-1)
275-
fgmask = seg > 0
276-
seg = seg[fgmask]
277-
seg_dict = {}
278-
for i in np.unique(seg):
279-
seg_dict[labels[i - 1]] = np.argwhere(seg == i).squeeze()
280-
281-
return data[fgmask], seg_dict
282-
283-
284230
def _get_tr(img):
285231
"""
286232
Attempt to extract repetition time from NIfTI/CIFTI header

niworkflows/interfaces/tests/test_plotting.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,8 @@
2424
import os
2525
import nibabel as nb
2626
from niworkflows import viz
27-
from niworkflows.interfaces.plotting import (
28-
_get_tr,
29-
_cifti_timeseries,
30-
_nifti_timeseries,
31-
)
27+
from niworkflows.utils.timeseries import _cifti_timeseries, _nifti_timeseries
28+
from niworkflows.interfaces.plotting import _get_tr
3229
from niworkflows.tests.conftest import datadir
3330

3431

niworkflows/tests/test_viz.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,8 @@
3333
from .generate_data import _create_dtseries_cifti
3434
from .. import viz
3535
from niworkflows.viz.plots import fMRIPlot
36-
from niworkflows.interfaces.plotting import (
37-
_cifti_timeseries,
38-
_nifti_timeseries,
39-
_get_tr,
40-
)
36+
from niworkflows.utils.timeseries import _cifti_timeseries, _nifti_timeseries
37+
from niworkflows.interfaces.plotting import _get_tr
4138

4239

4340
@pytest.mark.parametrize("tr", (None, 0.7))

niworkflows/utils/timeseries.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
2+
# vi: set ft=python sts=4 ts=4 sw=4 et:
3+
#
4+
# Copyright 2022 The NiPreps Developers <nipreps@gmail.com>
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
# We support and encourage derived works from this project, please read
19+
# about our expectations at
20+
#
21+
# https://www.nipreps.org/community/licensing/
22+
#
23+
"""Extracting signals from NIfTI and CIFTI2 files."""
24+
import numpy as np
25+
import nibabel as nb
26+
27+
28+
def _cifti_timeseries(dataset):
29+
"""Extract timeseries from CIFTI2 dataset."""
30+
dataset = nb.load(dataset) if isinstance(dataset, str) else dataset
31+
32+
if dataset.nifti_header.get_intent()[0] != "ConnDenseSeries":
33+
raise ValueError("Not a dense timeseries")
34+
35+
matrix = dataset.header.matrix
36+
labels = {
37+
"CIFTI_STRUCTURE_CORTEX_LEFT": "CtxL",
38+
"CIFTI_STRUCTURE_CORTEX_RIGHT": "CtxR",
39+
"CIFTI_STRUCTURE_CEREBELLUM_LEFT": "CbL",
40+
"CIFTI_STRUCTURE_CEREBELLUM_RIGHT": "CbR",
41+
}
42+
seg = {label: [] for label in list(labels.values()) + ["Other"]}
43+
for bm in matrix.get_index_map(1).brain_models:
44+
label = (
45+
"Other" if bm.brain_structure not in labels else
46+
labels[bm.brain_structure]
47+
)
48+
seg[label] += list(range(
49+
bm.index_offset, bm.index_offset + bm.index_count
50+
))
51+
52+
return dataset.get_fdata(dtype="float32").T, seg
53+
54+
55+
def _nifti_timeseries(
56+
dataset,
57+
segmentation=None,
58+
labels=("Ctx GM", "dGM", "WM+CSF", "Cb"),
59+
remap_rois=True,
60+
lut=None,
61+
):
62+
"""Extract timeseries from NIfTI1/2 datasets."""
63+
dataset = nb.load(dataset) if isinstance(dataset, str) else dataset
64+
data = dataset.get_fdata(dtype="float32").reshape((-1, dataset.shape[-1]))
65+
66+
if segmentation is None:
67+
return data, None
68+
69+
segmentation = nb.load(segmentation) if isinstance(segmentation, str) else segmentation
70+
# Map segmentation
71+
if remap_rois or lut is not None:
72+
if lut is None:
73+
lut = np.zeros((256,), dtype="int")
74+
lut[100:201] = 1 # Ctx GM
75+
lut[30:99] = 2 # dGM
76+
lut[1:11] = 3 # WM+CSF
77+
lut[255] = 4 # Cerebellum
78+
# Apply lookup table
79+
segmentation = lut[np.asanyarray(segmentation.dataobj, dtype=int)].reshape(-1)
80+
81+
fgmask = segmentation > 0
82+
segmentation = segmentation[fgmask]
83+
seg_dict = {}
84+
for i in np.unique(segmentation):
85+
seg_dict[labels[i - 1]] = np.argwhere(segmentation == i).squeeze()
86+
87+
return data[fgmask], seg_dict

0 commit comments

Comments
 (0)