diff --git a/src/fmripost_aroma/interfaces/reportlets.py b/src/fmripost_aroma/interfaces/reportlets.py
index 4a01917..728c85f 100644
--- a/src/fmripost_aroma/interfaces/reportlets.py
+++ b/src/fmripost_aroma/interfaces/reportlets.py
@@ -96,87 +96,74 @@ def _generate_segment(self):
raise NotImplementedError
-class _MELODICInputSpecRPT(nrb._SVGReportCapableInputSpec, fsl.model.MELODICInputSpec):
- out_report = File(
- 'melodic_reportlet.svg',
- usedefault=True,
- desc='Filename for the visual report generated by Nipype.',
- )
- report_mask = File(
- desc=(
- 'Mask used to draw the outline on the reportlet. '
- 'If not set the mask will be derived from the data.'
- ),
+class SubjectSummaryInputSpec(BaseInterfaceInputSpec):
+ subject_id = Str(desc='Subject ID')
+ bold = InputMultiObject(
+ traits.Either(File(exists=True), traits.List(File(exists=True))),
+ desc='BOLD functional series',
)
+ std_spaces = traits.List(Str, desc='list of standard spaces')
+ nstd_spaces = traits.List(Str, desc='list of non-standard spaces')
-class _MELODICOutputSpecRPT(
- reporting.ReportCapableOutputSpec,
- fsl.model.MELODICOutputSpec,
-):
- pass
-
-
-class MELODICRPT(fsl.MELODIC):
- """Create a reportlet for MELODIC outputs."""
-
- input_spec = _MELODICInputSpecRPT
- output_spec = _MELODICOutputSpecRPT
- _out_report = None
-
- def __init__(self, generate_report=False, **kwargs):
- """Create the reportlet."""
- super().__init__(**kwargs)
- self.generate_report = generate_report
-
- def _post_run_hook(self, runtime):
- # Run _post_run_hook of super class
- runtime = super()._post_run_hook(runtime)
- # leave early if there's nothing to do
- if not self.generate_report:
- return runtime
-
- NIWORKFLOWS_LOG.info('Generating report for MELODIC.')
- _melodic_dir = runtime.cwd
- if isdefined(self.inputs.out_dir):
- _melodic_dir = self.inputs.out_dir
- self._melodic_dir = os.path.abspath(_melodic_dir)
-
- self._out_report = self.inputs.out_report
- if not os.path.isabs(self._out_report):
- self._out_report = os.path.abspath(os.path.join(runtime.cwd, self._out_report))
-
- mix = os.path.join(self._melodic_dir, 'melodic_mix')
- if not os.path.exists(mix):
- NIWORKFLOWS_LOG.warning("MELODIC outputs not found, assuming it didn't converge.")
- self._out_report = self._out_report.replace('.svg', '.html')
- snippet = '
MELODIC did not converge, no output
'
- with open(self._out_report, 'w') as fobj:
- fobj.write(snippet)
- return runtime
-
- self._generate_report()
- return runtime
+class SubjectSummary(SummaryInterface):
+ input_spec = SubjectSummaryInputSpec
+ output_spec = SummaryOutputSpec
- def _list_outputs(self):
- try:
- outputs = super()._list_outputs()
- except NotImplementedError:
- outputs = {}
- if self._out_report is not None:
- outputs['out_report'] = self._out_report
- return outputs
+ def _generate_segment(self):
+ BIDS_NAME = re.compile(
+ r'^(.*\/)?'
+ '(?Psub-[a-zA-Z0-9]+)'
+ '(_(?Pses-[a-zA-Z0-9]+))?'
+ '(_(?Ptask-[a-zA-Z0-9]+))?'
+ '(_(?Pacq-[a-zA-Z0-9]+))?'
+ '(_(?Prec-[a-zA-Z0-9]+))?'
+ '(_(?Prun-[a-zA-Z0-9]+))?'
+ )
- def _generate_report(self):
- from niworkflows.viz.utils import plot_melodic_components
+ # Add list of tasks with number of runs
+ bold_series = self.inputs.bold if isdefined(self.inputs.bold) else []
+ bold_series = [s[0] if isinstance(s, list) else s for s in bold_series]
- plot_melodic_components(
- melodic_dir=self._melodic_dir,
- in_file=self.inputs.in_files[0],
- tr=self.inputs.tr_sec,
- out_file=self._out_report,
- compress=self.inputs.compress_report,
- report_mask=self.inputs.report_mask,
+ counts = Counter(
+ BIDS_NAME.search(series).groupdict()['task_id'][5:] for series in bold_series
+ )
+
+ tasks = ''
+ if counts:
+ header = '\t\t'
+ lines = [
+ '\t\t\tTask: {task_id} ({n_runs:d} run{s})'.format(
+ task_id=task_id, n_runs=n_runs, s='' if n_runs == 1 else 's'
+ )
+ for task_id, n_runs in sorted(counts.items())
+ ]
+ tasks = '\n'.join([header] + lines + [footer])
+
+ return SUBJECT_TEMPLATE.format(
+ subject_id=self.inputs.subject_id,
+ n_bold=len(bold_series),
+ tasks=tasks,
+ std_spaces=', '.join(self.inputs.std_spaces),
+ nstd_spaces=', '.join(self.inputs.nstd_spaces),
+ )
+
+
+class AboutSummaryInputSpec(BaseInterfaceInputSpec):
+ version = Str(desc='FMRIPREP version')
+ command = Str(desc='FMRIPREP command')
+ # Date not included - update timestamp only if version or command changes
+
+
+class AboutSummary(SummaryInterface):
+ input_spec = AboutSummaryInputSpec
+
+ def _generate_segment(self):
+ return ABOUT_TEMPLATE.format(
+ version=self.inputs.version,
+ command=self.inputs.command,
+ date=time.strftime('%Y-%m-%d %H:%M:%S %z'),
)
@@ -243,74 +230,3 @@ def _run_interface(self, runtime):
)
self._results['out_report'] = out_file
return runtime
-
-
-class SubjectSummaryInputSpec(BaseInterfaceInputSpec):
- subject_id = Str(desc='Subject ID')
- bold = InputMultiObject(
- traits.Either(File(exists=True), traits.List(File(exists=True))),
- desc='BOLD functional series',
- )
- std_spaces = traits.List(Str, desc='list of standard spaces')
- nstd_spaces = traits.List(Str, desc='list of non-standard spaces')
-
-
-class SubjectSummary(SummaryInterface):
- input_spec = SubjectSummaryInputSpec
- output_spec = SummaryOutputSpec
-
- def _generate_segment(self):
- BIDS_NAME = re.compile(
- r'^(.*\/)?'
- '(?Psub-[a-zA-Z0-9]+)'
- '(_(?Pses-[a-zA-Z0-9]+))?'
- '(_(?Ptask-[a-zA-Z0-9]+))?'
- '(_(?Pacq-[a-zA-Z0-9]+))?'
- '(_(?Prec-[a-zA-Z0-9]+))?'
- '(_(?Prun-[a-zA-Z0-9]+))?'
- )
-
- # Add list of tasks with number of runs
- bold_series = self.inputs.bold if isdefined(self.inputs.bold) else []
- bold_series = [s[0] if isinstance(s, list) else s for s in bold_series]
-
- counts = Counter(
- BIDS_NAME.search(series).groupdict()['task_id'][5:] for series in bold_series
- )
-
- tasks = ''
- if counts:
- header = '\t\t'
- lines = [
- '\t\t\tTask: {task_id} ({n_runs:d} run{s})'.format(
- task_id=task_id, n_runs=n_runs, s='' if n_runs == 1 else 's'
- )
- for task_id, n_runs in sorted(counts.items())
- ]
- tasks = '\n'.join([header] + lines + [footer])
-
- return SUBJECT_TEMPLATE.format(
- subject_id=self.inputs.subject_id,
- n_bold=len(bold_series),
- tasks=tasks,
- std_spaces=', '.join(self.inputs.std_spaces),
- nstd_spaces=', '.join(self.inputs.nstd_spaces),
- )
-
-
-class AboutSummaryInputSpec(BaseInterfaceInputSpec):
- version = Str(desc='FMRIPREP version')
- command = Str(desc='FMRIPREP command')
- # Date not included - update timestamp only if version or command changes
-
-
-class AboutSummary(SummaryInterface):
- input_spec = AboutSummaryInputSpec
-
- def _generate_segment(self):
- return ABOUT_TEMPLATE.format(
- version=self.inputs.version,
- command=self.inputs.command,
- date=time.strftime('%Y-%m-%d %H:%M:%S %z'),
- )
diff --git a/src/fmripost_aroma/workflows/aroma.py b/src/fmripost_aroma/workflows/aroma.py
index 360493b..6fb6d09 100644
--- a/src/fmripost_aroma/workflows/aroma.py
+++ b/src/fmripost_aroma/workflows/aroma.py
@@ -109,7 +109,7 @@ def init_ica_aroma_wf(
from fmripost_aroma.interfaces.confounds import ICAConfounds
from fmripost_aroma.interfaces.nilearn import MeanImage, MedianValue
- from fmripost_aroma.interfaces.reportlets import ICAAROMARPT, MELODICRPT
+ from fmripost_aroma.interfaces.reportlets import ICAAROMARPT
workflow = Workflow(name=_get_wf_name(bold_file, 'aroma'))
workflow.__postdesc__ = f"""\
@@ -200,7 +200,7 @@ def init_ica_aroma_wf(
# ICA with MELODIC
melodic = pe.Node(
- MELODICRPT(
+ fsl.MELODIC(
no_bet=True,
tr_sec=float(metadata['RepetitionTime']),
mm_thresh=0.5,
@@ -214,20 +214,6 @@ def init_ica_aroma_wf(
(smooth, melodic, [('smoothed_file', 'in_files')]),
]) # fmt:skip
- ds_report_melodic = pe.Node(
- DerivativesDataSink(
- base_directory=config.execution.fmripost_aroma_dir,
- source_file=bold_file,
- datatype='figures',
- desc='melodic',
- dismiss_entities=('echo', 'den', 'res'),
- ),
- name='ds_report_melodic',
- run_without_submitting=True,
- mem_gb=config.DEFAULT_MEMORY_MIN_GB,
- )
- workflow.connect([(melodic, ds_report_melodic, [('out_report', 'in_file')])])
-
select_melodic_files = pe.Node(
niu.Function(
function=_select_melodic_files,