Skip to content

Commit

Permalink
Merge pull request #162 from rwblair/issue155
Browse files Browse the repository at this point in the history
Issue155 [WIP]
  • Loading branch information
rwblair committed Oct 24, 2016
2 parents 7a602bb + 8f3f141 commit 739a04a
Show file tree
Hide file tree
Showing 15 changed files with 548 additions and 126 deletions.
3 changes: 2 additions & 1 deletion fmriprep/interfaces/bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def _list_outputs(self):
class DerivativesDataSinkInputSpec(BaseInterfaceInputSpec):
base_directory = traits.Directory(
desc='Path to the base directory for storing data.')
in_file = InputMultiPath(File(), exists=True, mandatory=True,
in_file = InputMultiPath(File(exists=True), mandatory=True,
desc='the object to be saved')
source_file = File(exists=True, mandatory=True, desc='the input func file')
suffix = traits.Str('', mandatory=True, desc='suffix appended to source_file')
Expand Down Expand Up @@ -125,6 +125,7 @@ def _run_interface(self, runtime):
out_path += '/{}'.format(mod)

out_path = op.join(base_directory, out_path)

make_folder(out_path)

base_fname = op.join(out_path, fname)
Expand Down
41 changes: 41 additions & 0 deletions fmriprep/viz/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"sub_reports":
[
{
"name": "Skull Strippings",
"elements":
[
{
"name": "t1_stripped_overlay",
"file_pattern": "t1_stripped_overlay",
"title": "Skull Stripped T1",
"description": "Stripped T1 placed over an image of the unstripped T1"
},
{
"name": "sbref_stripped_overlay",
"file_pattern": "sbref_stripped_overlay",
"title": "Skull Stripped Sbref",
"description": "Unwarped and stripped sbref with a background image of an unwarped sbref"
},
{
"name": "fmap_magnitude_stripped_overlay",
"file_pattern": "fmap_magnitude_stripped_overlay",
"title": "Skull Stripped Field Map Magnitude",
"description": "Stripped fieldmap magnitude estimated phase-difference image and one or more magnitude images corresponding to two or more gradient echo sequence acquisitions"
}
]
},
{
"name": "Registration Outputs",
"elements":
[
{
"name": "sbref_to_t1",
"file_pattern": "sbref_to_t1",
"title": "Sbref to T1",
"description": "Corrected sbref image registred into t1 space."
}
]
}
]
}
5 changes: 3 additions & 2 deletions fmriprep/viz/pdf_compose.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ def generate_report(output_file, first_plot, second_plot, third_plot,
fourth_plot, fifth_plot, sixth_plot, seventh_plot,
eighth_plot, t1_2_mni_plot=None):
import os.path

import pylab as plt
from matplotlib.gridspec import GridSpec
from matplotlib.backends.backend_pdf import PdfPages
import matplotlib.image as mimage
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib.gridspec import GridSpec

plots = [first_plot, second_plot, third_plot, fourth_plot,
fifth_plot, sixth_plot, seventh_plot, eighth_plot]
Expand Down
26 changes: 26 additions & 0 deletions fmriprep/viz/report.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.12: http://docutils.sourceforge.net/" />
<title></title>
<style type="text/css">
</style>
</head>
<body>



{% for sub_report in sub_reports %}
<h2>{{ sub_report.name }}</h2>
{% for elem in sub_report.elements %}
{{ elem.name }}
{% for image in elem.files_contents %}
{{ image }}
{% endfor %}
{% endfor %}
{% endfor %}

</body>
</html>
83 changes: 83 additions & 0 deletions fmriprep/viz/reports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from __future__ import unicode_literals

import codecs
import json
import re
import os
from os.path import join, exists, basename, dirname

import jinja2
from pkg_resources import resource_filename as pkgrf

class Element(object):

def __init__(self, name, file_pattern, title, description):
self.name = name
self.file_pattern = re.compile(file_pattern)
self.title = title
self.description = description
self.files = []
self.files_contents = []


class SubReport(object):

def __init__(self, name, elements, **kwargs):
self.name = name
self.elements = []
for e in elements:
element = Element(**e)
self.elements.append(element)

def generate_sub_report(self, report):
env = jinja2.Environment(
loader=jinja2.FileSystemLoader(searchpath='/'),
trim_blocks=True, lstrip_blocks=True
)
sub_report_tpl = env.get_template('{}_tpl.html'.format(self.name))
sub_report_render = sub_report_tpl.render
return sub_report_render

class Report(object):

def __init__(self, path, config, out_dir, out_filename='report.html'):
self.root = path
self.sub_reports = []
self._load_config(config)
self.out_dir = out_dir
self.out_filename = out_filename

def _load_config(self, config):
if isinstance(config, str):
config = json.load(open(config, 'r'))

for e in config['sub_reports']:
sub_report = SubReport(**e)
self.sub_reports.append(sub_report)

self.index()

def index(self):
for root, directories, filenames in os.walk(self.root):
for f in filenames:
f = join(root, f)
for sub_report in self.sub_reports:
for element in sub_report.elements:
if element.file_pattern.search(f) and f.split('.')[-1] == 'svg':
element.files.append(f)
with open(f) as fp:
content = fp.read()
content = '\n'.join(content.split('\n')[1:])
element.files_contents.append(content)

def generate_report(self):
searchpath = pkgrf('fmriprep', '/')
env = jinja2.Environment(
loader=jinja2.FileSystemLoader(searchpath=searchpath),
trim_blocks=True, lstrip_blocks=True
)
report_tpl = env.get_template('viz/report.tpl')
report_render = report_tpl.render(sub_reports=self.sub_reports)
with open(os.path.join(self.out_dir, self.out_filename), 'w') as fp:
fp.write(report_render)
return report_render
14 changes: 14 additions & 0 deletions fmriprep/viz/run_reports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from pkg_resources import resource_filename as pkgrf

from reports import Report

if __name__ == '__main__':
path = pkgrf('fmriprep', '../out/images/')
out_dir = pkgrf('fmriprep', '../out/')
config = pkgrf('fmriprep', 'viz/config.json')
report = Report(path, config, out_dir)
for sub_report in report.sub_reports:
for element in sub_report.elements:
print(element.files)
print(element.title)
print(report.generate_report())
95 changes: 69 additions & 26 deletions fmriprep/workflows/anatomical.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def t1w_preprocessing(name='t1w_preprocessing', settings=None):
num_threads=settings.get('ants_threads', 6), testing=settings.get('debug', False)),
name='T1_2_MNI_Registration')

# Resampe the brain mask and the tissue probability maps into mni space
# Resample the brain mask and the tissue probability maps into mni space
bmask_mni = pe.Node(ants.ApplyTransforms(
dimension=3, default_value=0, interpolation='NearestNeighbor'), name='brain_mni_warp')
bmask_mni.inputs.reference_image = op.join(get_mni_template(), 'MNI152_T1_1mm.nii.gz')
Expand Down Expand Up @@ -101,25 +101,53 @@ def t1w_preprocessing(name='t1w_preprocessing', settings=None):
])

# Connect reporting nodes
t1_stripped_overlay = pe.Node(niu.Function(
input_names=['in_file', 'overlay_file', 'out_file'], output_names=['out_file'],
function=stripped_brain_overlay), name='PNG_T1_SkullStrip')
t1_stripped_overlay.inputs.out_file = 't1_stripped_overlay.png'

# The T1-to-MNI will be plotted using the segmentation. That's why we transform it first
seg_2_mni = pe.Node(ants.ApplyTransforms(
dimension=3, default_value=0, interpolation='NearestNeighbor'), name='T1_2_MNI_warp')
seg_2_mni.inputs.reference_image = op.join(get_mni_template(), 'MNI152_T1_1mm.nii.gz')

t1_2_mni_overlay = pe.Node(niu.Function(
input_names=['in_file', 'overlay_file', 'out_file'], output_names=['out_file'],
function=stripped_brain_overlay), name='PNG_T1_to_MNI')
t1_2_mni_overlay.inputs.out_file = 't1_to_mni_overlay.png'
t1_2_mni_overlay.inputs.overlay_file = op.join(get_mni_template(), 'MNI152_T1_1mm.nii.gz')
t1_stripped_overlay = pe.Node(
niu.Function(
input_names=['in_file', 'overlay_file', 'out_file'],
output_names=['out_file'],
function=stripped_brain_overlay
),
name='PNG_T1_SkullStrip'
)
t1_stripped_overlay.inputs.out_file = 't1_stripped_overlay.svg'

# t1 segmentation mapped onto t1 before registration into mni space
t1_seg_native = pe.Node(
niu.Function(
input_names=['in_file', 'overlay_file', 'out_file'],
output_names=['out_file'],
function=stripped_brain_overlay
),
name='T1SegNative'
)
t1_seg_native.inputs.out_file = 't1_seg_native.svg'

# The T1-to-MNI will be plotted using the segmentation.
# That's why we transform it first
seg_2_mni = pe.Node(
ants.ApplyTransforms(dimension=3, default_value=0,
interpolation='NearestNeighbor'),
name='T1_2_MNI_warp'
)
seg_2_mni.inputs.reference_image = op.join(get_mni_template(),
'MNI152_T1_1mm.nii.gz')

t1_2_mni_overlay = pe.Node(
niu.Function(
input_names=['in_file', 'overlay_file', 'out_file'],
output_names=['out_file'],
function=stripped_brain_overlay
),
name='T1ToMNI'
)
t1_2_mni_overlay.inputs.out_file = 't1_to_mni_overlay.svg'
t1_2_mni_overlay.inputs.overlay_file = op.join(get_mni_template(),
'MNI152_T1_1mm.nii.gz')

datasink = pe.Node(
interface=nio.DataSink(
base_directory=op.join(settings['output_dir'], 'images')),
base_directory=op.join(settings['output_dir'], 'images')
),
name='datasink',
parameterization=False
)
Expand All @@ -133,32 +161,47 @@ def t1w_preprocessing(name='t1w_preprocessing', settings=None):
('forward_invert_flags', 'invert_transform_flags')]),
(seg_2_mni, t1_2_mni_overlay, [('output_image', 'in_file')]),
(t1_2_mni_overlay, datasink, [('out_file', '@t1_2_mni_overlay')]),
(t1_seg, t1_seg_native, [('tissue_class_map', 'in_file')]),
(inu_n4, t1_seg_native, [('output_image', 'overlay_file')]),
(t1_seg_native, datasink, [('out_file', '@t1_seg_native')])
])

# Write corrected file in the designated output dir
ds_t1_bias = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='inu'), name='DerivT1_inu')
suffix='inu'),
name='DerivT1_inu'
)
ds_t1_seg = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='inu_seg'), name='DerivT1_seg')
suffix='inu_seg'),
name='DerivT1_seg'
)
ds_mask = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='bmask'), name='DerivT1_mask')

suffix='bmask'),
name='DerivT1_mask'
)
ds_t1_mni = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='mni'), name='DerivT1w_MNI')
suffix='mni'),
name='DerivT1w_MNI'
)
ds_t1_mni_aff = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='mni_affine'), name='DerivT1w_MNI_affine')

suffix='mni_affine'),
name='DerivT1w_MNI_affine'
)
ds_bmask_mni = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='bmask_mni'), name='DerivT1_Mask_MNI')
suffix='bmask_mni'),
name='DerivT1_Mask_MNI'
)
ds_tpms_mni = pe.Node(
DerivativesDataSink(base_directory=settings['output_dir'],
suffix='tpm_mni'), name='DerivT1_TPMs_MNI')
suffix='tpm_mni'),
name='DerivT1_TPMs_MNI'
)

if settings.get('debug', False):
workflow.connect([
Expand Down
13 changes: 7 additions & 6 deletions fmriprep/workflows/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
@author: craigmoodie
"""
from copy import deepcopy

from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu
from nipype.interfaces import fsl
Expand Down Expand Up @@ -68,7 +70,7 @@ def wf_ds054_type(subject_data, settings, name='fMRI_prep'):
t1w_pre = t1w_preprocessing(settings=settings)

# Estimate fieldmap
fmap_est = phase_diff_and_magnitudes()
fmap_est = phase_diff_and_magnitudes(settings)

# Correct SBRef
sbref_pre = sbref_preprocess(settings=settings)
Expand All @@ -81,7 +83,7 @@ def wf_ds054_type(subject_data, settings, name='fMRI_prep'):
hmcwf.get_node('inputnode').iterables = ('epi', subject_data['func'])

# EPI to SBRef
epi2sbref = epi_sbref_registration()
epi2sbref = epi_sbref_registration(settings)

# EPI unwarp
epiunwarp_wf = epi_unwarp(settings=settings)
Expand All @@ -97,9 +99,10 @@ def wf_ds054_type(subject_data, settings, name='fMRI_prep'):
(t1w_pre, sbref_t1, [
('outputnode.t1_brain', 'inputnode.t1_brain'),
('outputnode.t1_seg', 'inputnode.t1_seg')]),
(sbref_pre, epi2sbref, [('outputnode.sbref_unwarped', 'inputnode.sbref_brain')]),
(sbref_pre, epi2sbref, [('outputnode.sbref_unwarped', 'inputnode.sbref_brain'),
('outputnode.sbref_unwarped_mask', 'inputnode.sbref_brain_mask')]),
(hmcwf, epi2sbref, [('outputnode.epi_brain', 'inputnode.epi_brain')]),

(hmcwf, epi2sbref, [('inputnode.epi', 'inputnode.epi')]),
(hmcwf, epiunwarp_wf, [('inputnode.epi', 'inputnode.epi')]),
(fmap_est, epiunwarp_wf, [('outputnode.fmap', 'inputnode.fmap'),
('outputnode.fmap_mask', 'inputnode.fmap_mask'),
Expand Down Expand Up @@ -145,11 +148,9 @@ def wf_ds005_type(subject_data, settings, name='fMRI_prep'):
# Apply transforms in 1 shot
epi_mni_trans_wf = epi_mni_transformation(settings=settings)


workflow.connect([
(bidssrc, t1w_pre, [('t1w', 'inputnode.t1w')]),
(hmcwf, epi_2_t1, [('inputnode.epi', 'inputnode.epi')]),

(hmcwf, epi_2_t1, [('outputnode.epi_mean', 'inputnode.epi_mean')]),
(t1w_pre, epi_2_t1, [('outputnode.t1_brain', 'inputnode.t1_brain'),
('outputnode.t1_seg', 'inputnode.t1_seg')]),
Expand Down

0 comments on commit 739a04a

Please sign in to comment.