diff --git a/.circleci/circle_bold.txt b/.circleci/circle_bold.txt index 6c28affc2..586f0af17 100644 --- a/.circleci/circle_bold.txt +++ b/.circleci/circle_bold.txt @@ -30,8 +30,14 @@ sub-ds205s03/figures/sub-ds205s03_task-view_run-02_desc-stdev_bold.svg sub-ds205s03/figures/sub-ds205s03_task-view_run-02_desc-zoomed_bold.svg sub-ds205s03/func sub-ds205s03/func/sub-ds205s03_task-functionallocalizer_run-01_bold.json +sub-ds205s03/func/sub-ds205s03_task-functionallocalizer_run-01_timeseries.json +sub-ds205s03/func/sub-ds205s03_task-functionallocalizer_run-01_timeseries.tsv sub-ds205s03/func/sub-ds205s03_task-view_run-01_bold.json +sub-ds205s03/func/sub-ds205s03_task-view_run-01_timeseries.json +sub-ds205s03/func/sub-ds205s03_task-view_run-01_timeseries.tsv sub-ds205s03/func/sub-ds205s03_task-view_run-02_bold.json +sub-ds205s03/func/sub-ds205s03_task-view_run-02_timeseries.json +sub-ds205s03/func/sub-ds205s03_task-view_run-02_timeseries.tsv sub-ds205s03_task-functionallocalizer_run-01_bold.html sub-ds205s03_task-view_run-01_bold.html sub-ds205s03_task-view_run-02_bold.html @@ -60,8 +66,14 @@ sub-ds205s07/figures/sub-ds205s07_task-view_run-02_desc-stdev_bold.svg sub-ds205s07/figures/sub-ds205s07_task-view_run-02_desc-zoomed_bold.svg sub-ds205s07/func sub-ds205s07/func/sub-ds205s07_task-functionallocalizer_run-01_bold.json +sub-ds205s07/func/sub-ds205s07_task-functionallocalizer_run-01_timeseries.json +sub-ds205s07/func/sub-ds205s07_task-functionallocalizer_run-01_timeseries.tsv sub-ds205s07/func/sub-ds205s07_task-view_run-01_bold.json +sub-ds205s07/func/sub-ds205s07_task-view_run-01_timeseries.json +sub-ds205s07/func/sub-ds205s07_task-view_run-01_timeseries.tsv sub-ds205s07/func/sub-ds205s07_task-view_run-02_bold.json +sub-ds205s07/func/sub-ds205s07_task-view_run-02_timeseries.json +sub-ds205s07/func/sub-ds205s07_task-view_run-02_timeseries.tsv sub-ds205s07_task-functionallocalizer_run-01_bold.html sub-ds205s07_task-view_run-01_bold.html sub-ds205s07_task-view_run-02_bold.html @@ -90,8 +102,14 @@ sub-ds205s09/figures/sub-ds205s09_task-view_acq-RL_run-01_desc-stdev_bold.svg sub-ds205s09/figures/sub-ds205s09_task-view_acq-RL_run-01_desc-zoomed_bold.svg sub-ds205s09/func sub-ds205s09/func/sub-ds205s09_task-view_acq-LR_run-01_bold.json +sub-ds205s09/func/sub-ds205s09_task-view_acq-LR_run-01_timeseries.json +sub-ds205s09/func/sub-ds205s09_task-view_acq-LR_run-01_timeseries.tsv sub-ds205s09/func/sub-ds205s09_task-view_acq-LR_run-02_bold.json +sub-ds205s09/func/sub-ds205s09_task-view_acq-LR_run-02_timeseries.json +sub-ds205s09/func/sub-ds205s09_task-view_acq-LR_run-02_timeseries.tsv sub-ds205s09/func/sub-ds205s09_task-view_acq-RL_run-01_bold.json +sub-ds205s09/func/sub-ds205s09_task-view_acq-RL_run-01_timeseries.json +sub-ds205s09/func/sub-ds205s09_task-view_acq-RL_run-01_timeseries.tsv sub-ds205s09_task-view_acq-LR_run-01_bold.html sub-ds205s09_task-view_acq-LR_run-02_bold.html sub-ds205s09_task-view_acq-RL_run-01_bold.html diff --git a/mriqc/data/bootstrap-func.yml b/mriqc/data/bootstrap-func.yml index 659c3b5e8..5e34fc115 100644 --- a/mriqc/data/bootstrap-func.yml +++ b/mriqc/data/bootstrap-func.yml @@ -37,10 +37,28 @@ sections: - bids: {datatype: figures, desc: stdev} subtitle: Standard deviation of signal through time caption: The voxel-wise standard deviation of the signal (variability along time). + - bids: {datatype: figures, desc: background} + caption: This panel shows a mosaic enhancing the background around the head. + Artifacts usually unveil themselves in the air surrounding the head, where no signal + sources are present. + subtitle: View of the background of the voxel-wise average of the BOLD timeseries + - bids: {datatype: figures, desc: zoomed} + caption: This panel shows a mosaic of the brain. This mosaic is the most suitable to + screen head-motion intensity inhomogeneities, global/local noise, signal leakage + (for example, from the eyeballs and across the phase-encoding axis), etc. + subtitle: Voxel-wise average of BOLD time-series, zoomed-in covering just the brain - bids: {datatype: figures, desc: carpet} subtitle: Carpetplot and nuisance signals caption: The so-called «carpetplot» may assist in assessing head-motion derived artifacts and respiation effects. + +- name: Extended echo-wise reports + ordering: echo + reportlets: + - bids: {datatype: figures, desc: mean} + subtitle: Voxel-wise average of BOLD time-series + caption: The average signal calculated across the last axis (time). + - name: Extended reports shared across echos reportlets: - bids: {datatype: figures, desc: brainmask} @@ -54,23 +72,6 @@ sections: subtitle: Spatial normalization of the anatomical image static: false -- name: Extended echo-wise reports - ordering: echo - reportlets: - - bids: {datatype: figures, desc: background} - caption: This panel shows a mosaic enhancing the background around the head. - Artifacts usually unveil themselves in the air surrounding the head, where no signal - sources are present. - subtitle: View of the background of the voxel-wise average of the BOLD timeseries - - bids: {datatype: figures, desc: mean} - subtitle: Average signal through time - caption: The average signal calculated across the last axis (time). - - bids: {datatype: figures, desc: zoomed} - caption: This panel shows a mosaic of the brain. This mosaic is the most suitable to - screen head-motion intensity inhomogeneities, global/local noise, signal leakage - (for example, from the eyeballs and across the phase-encoding axis), etc. - subtitle: Voxel-wise average of BOLD time-series, zoomed-in covering just the brain - - name: About nested: true reportlets: diff --git a/mriqc/interfaces/__init__.py b/mriqc/interfaces/__init__.py index 645ce7b25..de5cac733 100644 --- a/mriqc/interfaces/__init__.py +++ b/mriqc/interfaces/__init__.py @@ -32,7 +32,7 @@ ) from mriqc.interfaces.bids import IQMFileSink from mriqc.interfaces.common import ConformImage, EnsureSize -from mriqc.interfaces.functional import FunctionalQC, Spikes +from mriqc.interfaces.functional import FunctionalQC, GatherTimeseries, Spikes from mriqc.interfaces.webapi import UploadIQMs @@ -47,6 +47,7 @@ class DerivativesDataSink(_DDSink): "DerivativesDataSink", "EnsureSize", "FunctionalQC", + "GatherTimeseries", "Harmonize", "IQMFileSink", "RotationMask", diff --git a/mriqc/interfaces/functional.py b/mriqc/interfaces/functional.py index dd72af0f6..0f644e24b 100644 --- a/mriqc/interfaces/functional.py +++ b/mriqc/interfaces/functional.py @@ -38,6 +38,8 @@ traits, Undefined, ) +from nipype.utils.misc import normalize_mc_params +import pandas as pd class FunctionalQCInputSpec(BaseInterfaceInputSpec): @@ -309,6 +311,185 @@ def _run_interface(self, runtime): return runtime +class GatherTimeseriesInputSpec(TraitedSpec): + dvars = File(exists=True, mandatory=True, desc='file containing DVARS') + fd = File(exists=True, mandatory=True, desc='input framewise displacement') + mpars = File(exists=True, mandatory=True, desc='input motion parameters') + mpars_source = traits.Enum( + "FSL", + "AFNI", + "SPM", + "FSFAST", + "NIPY", + desc="Source of movement parameters", + mandatory=True, + ) + outliers = File( + exists=True, + mandatory=True, + desc="input file containing timeseries of AFNI's outlier count") + quality = File( + exists=True, + mandatory=True, + desc="input file containing AFNI's Quality Index") + + +class GatherTimeseriesOutputSpec(TraitedSpec): + timeseries_file = File(desc='output confounds file') + timeseries_metadata = traits.Dict(desc='Metadata dictionary describing columns') + + +class GatherTimeseries(SimpleInterface): + """ + Gather quality metrics that are timeseries into one TSV file + + """ + input_spec = GatherTimeseriesInputSpec + output_spec = GatherTimeseriesOutputSpec + + def _run_interface(self, runtime): + + # motion parameters + mpars = np.apply_along_axis( + func1d=normalize_mc_params, + axis=1, + arr=np.loadtxt(self.inputs.mpars), # mpars is N_t x 6 + source=self.inputs.mpars_source, + ) + timeseries = pd.DataFrame( + mpars, + columns=[ + "trans_x", + "trans_y", + "trans_z", + "rot_x", + "rot_y", + "rot_z" + ]) + + # DVARS + dvars = pd.read_csv( + self.inputs.dvars, + delim_whitespace=True, + skiprows=1, # column names have spaces + header=None, + names=["dvars_std", "dvars_nstd", "dvars_vstd"]) + dvars.index = pd.RangeIndex(1, timeseries.index.max() + 1) + + # FD + fd = pd.read_csv( + self.inputs.fd, + delim_whitespace=True, + header=0, + names=["framewise_displacement"]) + fd.index = pd.RangeIndex(1, timeseries.index.max() + 1) + + # AQI + aqi = pd.read_csv( + self.inputs.quality, + delim_whitespace=True, + header=None, + names=["aqi"]) + + # Outliers + aor = pd.read_csv( + self.inputs.outliers, + delim_whitespace=True, + header=None, + names=["aor"]) + + timeseries = pd.concat((timeseries, dvars, fd, aqi, aor), axis=1) + + timeseries_file = op.join(runtime.cwd, "timeseries.tsv") + + timeseries.to_csv(timeseries_file, sep='\t', index=False, na_rep='n/a') + + self._results['timeseries_file'] = timeseries_file + self._results['timeseries_metadata'] = _build_timeseries_metadata() + return runtime + + +def _build_timeseries_metadata(): + return { + "trans_x": { + "LongName": "Translation Along X Axis", + "Description": "Estimated Motion Parameter", + "Units": "mm" + }, + "trans_y": { + "LongName": "Translation Along Y Axis", + "Description": "Estimated Motion Parameter", + "Units": "mm" + }, + "trans_z": { + "LongName": "Translation Along Z Axis", + "Description": "Estimated Motion Parameter", + "Units": "mm", + }, + "rot_x": { + "LongName": "Rotation Around X Axis", + "Description": "Estimated Motion Parameter", + "Units": "rad" + }, + "rot_y": { + "LongName": "Rotation Around X Axis", + "Description": "Estimated Motion Parameter", + "Units": "rad" + }, + "rot_z": { + "LongName": "Rotation Around X Axis", + "Description": "Estimated Motion Parameter", + "Units": "rad" + }, + "dvars_std": { + "LongName": "Derivative of RMS Variance over Voxels, Standardized", + "Description": ( + "Indexes the rate of change of BOLD signal across" + "the entire brain at each frame of data, normalized with the" + "standard deviation of the temporal difference time series" + ) + }, + "dvars_nstd": { + "LongName": ( + "Derivative of RMS Variance over Voxels," + "Non-Standardized" + ), + "Description": ( + "Indexes the rate of change of BOLD signal across" + "the entire brain at each frame of data, not normalized." + ) + }, + "dvars_vstd": { + "LongName": "Derivative of RMS Variance over Voxels, Standardized", + "Description": ( + "Indexes the rate of change of BOLD signal across" + "the entire brain at each frame of data, normalized across" + "time by that voxel standard deviation across time," + "before computing the RMS of the temporal difference" + ) + }, + "framewise_displacement": { + "LongName": "Framewise Displacement", + "Description": ( + "A quantification of the estimated bulk-head" + "motion calculated using formula proposed by Power (2012)" + ), + "Units": "mm" + }, + "aqi": { + "LongName": "AFNI's Quality Index", + "Description": "Mean quality index as computed by AFNI's 3dTqual" + }, + "aor": { + "LongName": "AFNI's Fraction of Outliers per Volume", + "Description": ( + "Mean fraction of outliers per fMRI volume as" + "given by AFNI's 3dToutcount" + ) + } + } + + def find_peaks(data): t_z = [data[:, :, i, :].mean(axis=0).mean(axis=0) for i in range(data.shape[2])] return t_z diff --git a/mriqc/reports/group.py b/mriqc/reports/group.py index 2417dd957..1577fb3b6 100644 --- a/mriqc/reports/group.py +++ b/mriqc/reports/group.py @@ -200,6 +200,7 @@ def gen_html(csv_file, mod, csv_failed=None, out_file=None): None, ), ], + "dwi": [], } if csv_file.suffix == ".csv": diff --git a/mriqc/workflows/diffusion/output.py b/mriqc/workflows/diffusion/output.py index e0ab8260e..d7346be6c 100644 --- a/mriqc/workflows/diffusion/output.py +++ b/mriqc/workflows/diffusion/output.py @@ -44,7 +44,7 @@ def init_dwi_report_wf(name="dwi_report_wf"): wf = init_dwi_report_wf() """ - from niworkflows.interfaces.plotting import FMRISummary + from nireports.interfaces import FMRISummary from niworkflows.interfaces.morphology import BinaryDilation, BinarySubtraction from nireports.interfaces import PlotMosaic, PlotSpikes diff --git a/mriqc/workflows/functional/base.py b/mriqc/workflows/functional/base.py index 3db1cb224..abe4ed1bb 100644 --- a/mriqc/workflows/functional/base.py +++ b/mriqc/workflows/functional/base.py @@ -177,7 +177,8 @@ def fmri_qc_workflow(name="funcMRIQC"): (sanitize, iqmswf, [("out_file", "inputnode.in_ras")]), (mean, iqmswf, [("out_file", "inputnode.epi_mean")]), (hmcwf, iqmswf, [("outputnode.out_file", "inputnode.hmc_epi"), - ("outputnode.out_fd", "inputnode.hmc_fd")]), + ("outputnode.out_fd", "inputnode.hmc_fd"), + ("outputnode.mpars", "inputnode.mpars")]), (tsnr, iqmswf, [("tsnr_file", "inputnode.in_tsnr")]), (non_steady_state_detector, iqmswf, [("n_volumes_to_discard", "inputnode.exclude_index")]), # Feed reportlet generation @@ -282,7 +283,12 @@ def compute_iqms(name="ComputeIQMs"): from nipype.algorithms.confounds import ComputeDVARS from nipype.interfaces.afni import OutlierCount, QualityIndex - from mriqc.interfaces import FunctionalQC, IQMFileSink + from mriqc.interfaces import ( + DerivativesDataSink, + FunctionalQC, + IQMFileSink, + GatherTimeseries + ) from mriqc.interfaces.reports import AddProvenance from mriqc.interfaces.transitional import GCOR from mriqc.workflows.utils import _tofloat, get_fwhmx @@ -302,6 +308,7 @@ def compute_iqms(name="ComputeIQMs"): "fd_thres", "in_tsnr", "metadata", + "mpars", "exclude_index", "subject", "session", @@ -365,6 +372,13 @@ def compute_iqms(name="ComputeIQMs"): iterfield=["in_epi", "in_hmc", "in_tsnr", "in_dvars", "in_fwhm"], ) + timeseries = pe.MapNode( + GatherTimeseries(mpars_source="AFNI"), + name="timeseries", + mem_gb=mem_gb * 3, + iterfield=["dvars", "outliers", "quality", "fd"] + ) + # fmt: off workflow.connect([ (inputnode, dvnode, [("hmc_epi", "in_file"), @@ -385,7 +399,11 @@ def compute_iqms(name="ComputeIQMs"): (dvnode, measures, [("out_all", "in_dvars")]), (fwhm, measures, [(("fwhm", _tofloat), "in_fwhm")]), (dvnode, outputnode, [("out_all", "out_dvars")]), - (outliers, outputnode, [("out_file", "outliers")]) + (outliers, outputnode, [("out_file", "outliers")]), + (outliers, timeseries, [("out_file", "outliers")]), + (quality, timeseries, [("out_file", "quality")]), + (dvnode, timeseries, [("out_all", "dvars")]), + (inputnode, timeseries, [("hmc_fd", "fd"), ("mpars", "mpars")]), ]) # fmt: on @@ -408,6 +426,17 @@ def compute_iqms(name="ComputeIQMs"): iterfield=["in_file", "root", "metadata", "provenance"], ) + # Save timeseries TSV file + ds_timeseries = pe.MapNode( + DerivativesDataSink( + base_directory=str(config.execution.output_dir), + suffix="timeseries" + ), + name="ds_timeseries", + run_without_submitting=True, + iterfield=["in_file", "source_file", "meta_dict"], + ) + # fmt: off workflow.connect([ (inputnode, addprov, [("in_file", "in_file")]), @@ -426,6 +455,9 @@ def compute_iqms(name="ComputeIQMs"): (quality, datasink, [(("out_file", _parse_tqual), "aqi")]), (measures, datasink, [("out_qc", "root")]), (datasink, outputnode, [("out_file", "out_file")]), + (inputnode, ds_timeseries, [("in_file", "source_file")]), + (timeseries, ds_timeseries, [("timeseries_file", "in_file"), + ("timeseries_metadata", "meta_dict")]), ]) # fmt: on @@ -509,7 +541,10 @@ def hmc(name="fMRI_HMC", omp_nthreads=None): name="inputnode", ) - outputnode = pe.Node(niu.IdentityInterface(fields=["out_file", "out_fd"]), name="outputnode") + outputnode = pe.Node( + niu.IdentityInterface(fields=["out_file", "out_fd", "mpars"]), + name="outputnode", + ) # calculate hmc parameters estimate_hm = pe.Node( @@ -539,6 +574,7 @@ def hmc(name="fMRI_HMC", omp_nthreads=None): (estimate_hm, apply_hmc, [("oned_matrix_save", "in_xfm")]), (apply_hmc, outputnode, [("out", "out_file")]), (estimate_hm, fdnode, [("oned_file", "in_file")]), + (estimate_hm, outputnode, [("oned_file", "mpars")]), (fdnode, outputnode, [("out_file", "out_fd")]), ]) # fmt: on diff --git a/mriqc/workflows/functional/output.py b/mriqc/workflows/functional/output.py index 9761ccdd9..72a1d2328 100644 --- a/mriqc/workflows/functional/output.py +++ b/mriqc/workflows/functional/output.py @@ -40,7 +40,7 @@ def init_func_report_wf(name="func_report_wf"): wf = init_func_report_wf() """ - from niworkflows.interfaces.plotting import FMRISummary + from nireports.interfaces import FMRISummary from niworkflows.interfaces.morphology import BinaryDilation, BinarySubtraction from nireports.interfaces import PlotMosaic, PlotSpikes @@ -151,12 +151,35 @@ def init_func_report_wf(name="func_report_wf"): iterfield=["in_file"], ) + mosaic_zoom = pe.MapNode( + PlotMosaic( + cmap="Greys_r", + ), + name="PlotMosaicZoomed", + iterfield=["in_file"], + ) + + mosaic_noise = pe.MapNode( + PlotMosaic( + only_noise=True, + cmap="viridis_r", + ), + name="PlotMosaicNoise", + iterfield=["in_file"], + ) + + if config.workflow.species.lower() in ("rat", "mouse"): + mosaic_mean.inputs.view = ["coronal", "axial"] + mosaic_stddev.inputs.view = ["coronal", "axial"] + mosaic_zoom.inputs.view = ["coronal", "axial"] + mosaic_noise.inputs.view = ["coronal", "axial"] + ds_report_mean = pe.MapNode( DerivativesDataSink( base_directory=reportlets_dir, desc="mean", datatype="figures", - dismiss_entities=("part",) + dismiss_entities=("part",), ), name="ds_report_mean", run_without_submitting=True, @@ -168,19 +191,43 @@ def init_func_report_wf(name="func_report_wf"): base_directory=reportlets_dir, desc="stdev", datatype="figures", - dismiss_entities=("part",) + dismiss_entities=("part",), ), name="ds_report_stdev", run_without_submitting=True, iterfield=["in_file", "source_file"], ) + ds_report_background = pe.MapNode( + DerivativesDataSink( + base_directory=reportlets_dir, + desc="background", + datatype="figures", + dismiss_entities=("part",), + ), + name="ds_report_background", + run_without_submitting=True, + iterfield=["in_file", "source_file"], + ) + + ds_report_zoomed = pe.MapNode( + DerivativesDataSink( + base_directory=reportlets_dir, + desc="zoomed", + datatype="figures", + dismiss_entities=("part",), + ), + name="ds_report_zoomed", + run_without_submitting=True, + iterfield=["in_file", "source_file"], + ) + ds_report_carpet = pe.MapNode( DerivativesDataSink( base_directory=reportlets_dir, desc="carpet", datatype="figures", - dismiss_entities=("part",) + dismiss_entities=("part",), ), name="ds_report_carpet", run_without_submitting=True, @@ -194,9 +241,16 @@ def init_func_report_wf(name="func_report_wf"): (inputnode, mosaic_stddev, [("in_stddev", "in_file")]), (inputnode, ds_report_mean, [("name_source", "source_file")]), (inputnode, ds_report_stdev, [("name_source", "source_file")]), + (inputnode, ds_report_background, [("name_source", "source_file")]), + (inputnode, ds_report_zoomed, [("name_source", "source_file")]), (inputnode, ds_report_carpet, [("name_source", "source_file")]), + (inputnode, mosaic_zoom, [("epi_mean", "in_file"), + ("brainmask", "bbox_mask_file")]), + (inputnode, mosaic_noise, [("epi_mean", "in_file")]), (mosaic_mean, ds_report_mean, [("out_file", "in_file")]), (mosaic_stddev, ds_report_stdev, [("out_file", "in_file")]), + (mosaic_noise, ds_report_background, [("out_file", "in_file")]), + (mosaic_zoom, ds_report_zoomed, [("out_file", "in_file")]), (bigplot, ds_report_carpet, [("out_file", "in_file")]), ]) # fmt: on @@ -216,7 +270,7 @@ def init_func_report_wf(name="func_report_wf"): base_directory=reportlets_dir, desc="spikes", datatype="figures", - dismiss_entities=("part",) + dismiss_entities=("part",), ), name="ds_report_spikes", run_without_submitting=True, @@ -239,29 +293,6 @@ def init_func_report_wf(name="func_report_wf"): from niworkflows.utils.connections import pop_file as _pop from nireports.interfaces import PlotContours - mosaic_zoom = pe.MapNode( - PlotMosaic( - cmap="Greys_r", - ), - name="PlotMosaicZoomed", - iterfield=["in_file"], - ) - - mosaic_noise = pe.MapNode( - PlotMosaic( - only_noise=True, - cmap="viridis_r", - ), - name="PlotMosaicNoise", - iterfield=["in_file"] - ) - - if config.workflow.species.lower() in ("rat", "mouse"): - mosaic_mean.inputs.view = ["coronal", "axial"] - mosaic_stddev.inputs.view = ["coronal", "axial"] - mosaic_zoom.inputs.view = ["coronal", "axial"] - mosaic_noise.inputs.view = ["coronal", "axial"] - plot_bmask = pe.Node( PlotContours( display_mode="y" if config.workflow.species.lower() in ("rat", "mouse") else "z", @@ -273,30 +304,6 @@ def init_func_report_wf(name="func_report_wf"): name="PlotBrainmask", ) - ds_report_zoomed = pe.MapNode( - DerivativesDataSink( - base_directory=reportlets_dir, - desc="zoomed", - datatype="figures", - dismiss_entities=("part",) - ), - name="ds_report_zoomed", - run_without_submitting=True, - iterfield=["in_file", "source_file"], - ) - - ds_report_background = pe.MapNode( - DerivativesDataSink( - base_directory=reportlets_dir, - desc="background", - datatype="figures", - dismiss_entities=("part",) - ), - name="ds_report_background", - run_without_submitting=True, - iterfield=["in_file", "source_file"], - ) - ds_report_bmask = pe.Node( DerivativesDataSink( base_directory=reportlets_dir, @@ -325,14 +332,7 @@ def init_func_report_wf(name="func_report_wf"): ("name_source", "source_file")]), (inputnode, plot_bmask, [(("epi_mean", _pop), "in_file"), ("brainmask", "in_contours")]), - (inputnode, mosaic_zoom, [("epi_mean", "in_file"), - ("brainmask", "bbox_mask_file")]), - (inputnode, mosaic_noise, [("epi_mean", "in_file")]), - (inputnode, ds_report_zoomed, [("name_source", "source_file")]), - (inputnode, ds_report_background, [("name_source", "source_file")]), (inputnode, ds_report_bmask, [("name_source", "source_file")]), - (mosaic_zoom, ds_report_zoomed, [("out_file", "in_file")]), - (mosaic_noise, ds_report_background, [("out_file", "in_file")]), (plot_bmask, ds_report_bmask, [(("out_file", _pop), "in_file")]), ]) # fmt: on