-
Notifications
You must be signed in to change notification settings - Fork 37
/
reports.py
117 lines (89 loc) · 3.93 KB
/
reports.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
"""
Interfaces to generate reportlets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
from pathlib import Path
import time
from nipype.interfaces.base import (
TraitedSpec, BaseInterfaceInputSpec,
File, Directory, InputMultiObject, Str, isdefined,
SimpleInterface)
from nipype.interfaces import freesurfer as fs
SUBJECT_TEMPLATE = """\
\t<ul class="elem-desc">
\t\t<li>Subject ID: {subject_id}</li>
\t\t<li>Structural images: {n_t1s:d} T1-weighted {t2w}</li>
\t\t<li>Standard spaces: {output_spaces}</li>
\t\t<li>FreeSurfer reconstruction: {freesurfer_status}</li>
\t</ul>
"""
ABOUT_TEMPLATE = """\t<ul>
\t\t<li>sMRIPrep version: {version}</li>
\t\t<li>sMRIPrep command: <code>{command}</code></li>
\t\t<li>Date preprocessed: {date}</li>
\t</ul>
</div>
"""
class SummaryOutputSpec(TraitedSpec):
out_report = File(exists=True, desc='HTML segment containing summary')
class SummaryInterface(SimpleInterface):
output_spec = SummaryOutputSpec
def _run_interface(self, runtime):
segment = self._generate_segment()
path = Path(runtime.cwd) / 'report.html'
path.write_text(segment)
self._results['out_report'] = str(path)
return runtime
def _generate_segment(self):
raise NotImplementedError
class SubjectSummaryInputSpec(BaseInterfaceInputSpec):
t1w = InputMultiObject(File(exists=True), desc='T1w structural images')
t2w = InputMultiObject(File(exists=True), desc='T2w structural images')
subjects_dir = Directory(desc='FreeSurfer subjects directory')
subject_id = Str(desc='Subject ID')
output_spaces = InputMultiObject(Str, desc='list of standard spaces')
class SubjectSummaryOutputSpec(SummaryOutputSpec):
# This exists to ensure that the summary is run prior to the first ReconAll
# call, allowing a determination whether there is a pre-existing directory
subject_id = Str(desc='FreeSurfer subject ID')
class SubjectSummary(SummaryInterface):
input_spec = SubjectSummaryInputSpec
output_spec = SubjectSummaryOutputSpec
def _run_interface(self, runtime):
if isdefined(self.inputs.subject_id):
self._results['subject_id'] = self.inputs.subject_id
return super(SubjectSummary, self)._run_interface(runtime)
def _generate_segment(self):
if not isdefined(self.inputs.subjects_dir):
freesurfer_status = 'Not run'
else:
recon = fs.ReconAll(subjects_dir=self.inputs.subjects_dir,
subject_id=self.inputs.subject_id,
T1_files=self.inputs.t1w,
flags='-noskullstrip')
if recon.cmdline.startswith('echo'):
freesurfer_status = 'Pre-existing directory'
else:
freesurfer_status = 'Run by sMRIPrep'
t2w_seg = ''
if self.inputs.t2w:
t2w_seg = '(+ {:d} T2-weighted)'.format(len(self.inputs.t2w))
return SUBJECT_TEMPLATE.format(subject_id=self.inputs.subject_id,
n_t1s=len(self.inputs.t1w),
t2w=t2w_seg,
output_spaces=', '.join(self.inputs.output_spaces),
freesurfer_status=freesurfer_status)
class AboutSummaryInputSpec(BaseInterfaceInputSpec):
version = Str(desc='sMRIPrep version')
command = Str(desc='sMRIPrep 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"))