From 69435bcce59debe757b01ebfc1fcd8d2c411189a Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Wed, 3 Aug 2016 20:57:40 -0700 Subject: [PATCH 1/5] [ENH] Implement missing inputs/outputs in avscale --- nipype/interfaces/fsl/__init__.py | 2 +- nipype/interfaces/fsl/utils.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/nipype/interfaces/fsl/__init__.py b/nipype/interfaces/fsl/__init__.py index b2f524b3be..4ef2a04e85 100644 --- a/nipype/interfaces/fsl/__init__.py +++ b/nipype/interfaces/fsl/__init__.py @@ -12,7 +12,7 @@ from .model import (Level1Design, FEAT, FEATModel, FILMGLS, FEATRegister, FLAMEO, ContrastMgr, MultipleRegressDesign, L2Model, SMM, MELODIC, SmoothEstimate, Cluster, Randomise, GLM) -from .utils import (Smooth, Merge, ExtractROI, Split, ImageMaths, ImageMeants, +from .utils import (AvScale, Smooth, Merge, ExtractROI, Split, ImageMaths, ImageMeants, ImageStats, FilterRegressor, Overlay, Slicer, PlotTimeSeries, PlotMotionParams, ConvertXFM, SwapDimensions, PowerSpectrum, Reorient2Std, diff --git a/nipype/interfaces/fsl/utils.py b/nipype/interfaces/fsl/utils.py index 3edc3a73e6..8d261c023e 100644 --- a/nipype/interfaces/fsl/utils.py +++ b/nipype/interfaces/fsl/utils.py @@ -609,8 +609,11 @@ def aggregate_outputs(self, runtime=None, needed_outputs=None): class AvScaleInputSpec(FSLCommandInputSpec): - mat_file = File(exists=True, argstr="%s", - desc='mat file to read', position=0) + all_param = traits.Bool(False, argstr='--allparams') + mat_file = File(exists=True, argstr='%s', + desc='mat file to read', position=-2) + ref_file = File(exists=True, argstr='%s', position=-1, + desc='reference file to get center of rotation') class AvScaleOutputSpec(TraitedSpec): From 869a9dfb825044fad73c05323ead0d4c1eb1b711 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Thu, 4 Aug 2016 00:27:57 -0700 Subject: [PATCH 2/5] completing AvScale --- nipype/interfaces/fsl/utils.py | 71 ++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/nipype/interfaces/fsl/utils.py b/nipype/interfaces/fsl/utils.py index 8d261c023e..64f1b847d2 100644 --- a/nipype/interfaces/fsl/utils.py +++ b/nipype/interfaces/fsl/utils.py @@ -617,16 +617,20 @@ class AvScaleInputSpec(FSLCommandInputSpec): class AvScaleOutputSpec(TraitedSpec): - rotation_translation_matrix = traits.Any( - desc='Rotation and Translation Matrix') - scales = traits.Any(desc='Scales (x,y,z)') - skews = traits.Any(desc='Skews') - average_scaling = traits.Any(desc='Average Scaling') - determinant = traits.Any(desc='Determinant') - forward_half_transform = traits.Any(desc='Forward Half Transform') - backward_half_transform = traits.Any(desc='Backwards Half Transform') + rotation_translation_matrix = traits.List( + traits.List(traits.Float), desc='Rotation and Translation Matrix') + scales = traits.List(traits.Float, desc='Scales (x,y,z)') + skews = traits.List(traits.Float, desc='Skews') + average_scaling = traits.Float(desc='Average Scaling') + determinant = traits.Float(desc='Determinant') + forward_half_transform = traits.List( + traits.List(traits.Float), desc='Forward Half Transform') + backward_half_transform = traits.List( + traits.List(traits.Float), desc='Backwards Half Transform') left_right_orientation_preserved = traits.Bool( desc='True if LR orientation preserved') + rot_angles = traits.List(traits.Float, desc='rotation angles') + translations = traits.List(traits.Float, desc='translations') class AvScale(FSLCommand): @@ -652,26 +656,37 @@ def _format_arg(self, name, trait_spec, value): def aggregate_outputs(self, runtime=None, needed_outputs=None): outputs = self._outputs() - def lines_to_float(lines): - out = [] - for line in lines: - values = line.split() - out.append([float(val) for val in values]) - return out - - out = runtime.stdout.split('\n') - - outputs.rotation_translation_matrix = lines_to_float(out[1:5]) - outputs.scales = lines_to_float([out[6].split(" = ")[1]]) - outputs.skews = lines_to_float([out[8].split(" = ")[1]]) - outputs.average_scaling = lines_to_float([out[10].split(" = ")[1]]) - outputs.determinant = lines_to_float([out[12].split(" = ")[1]]) - if out[13].split(": ")[1] == 'preserved': - outputs.left_right_orientation_preserved = True - else: - outputs.left_right_orientation_preserved = False - outputs.forward_half_transform = lines_to_float(out[16:20]) - outputs.backward_half_transform = lines_to_float(out[22:-1]) + expr = re.compile( + 'Rotation\ &\ Translation\ Matrix:\n(?P[0-9\.\ \n-]+)[\s\n]*' + '(Rotation\ Angles\ \(x,y,z\)\ \[rads\]\ =\ (?P[0-9\.\ -]+))?[\s\n]*' + '(Translations\ \(x,y,z\)\ \[mm\]\ =\ (?P[0-9\.\ -]+))?[\s\n]*' + 'Scales\ \(x,y,z\)\ =\ (?P[0-9\.\ -]+)[\s\n]*' + 'Skews\ \(xy,xz,yz\)\ =\ (?P[0-9\.\ -]+)[\s\n]*' + 'Average\ scaling\ =\ (?P[0-9\.-]+)[\s\n]*' + 'Determinant\ =\ (?P[0-9\.-]+)[\s\n]*' + 'Left-Right\ orientation:\ (?P[A-Za-z]+)[\s\n]*' + 'Forward\ half\ transform\ =[\s]*\n' + '(?P[0-9\.\ \n-]+)[\s\n]*' + 'Backward\ half\ transform\ =[\s]*\n' + '(?P[0-9\.\ \n-]+)[\s\n]*') + + out = expr.search(runtime.stdout).groupdict() + + outputs['rotation_translation_matrix'] = [ + float(v) for v in r.split(' ') for r in out['rot_tran_mat'].strip().split('\n')] + outputs['scales'] = [float(s) for s in out['scales'].strip()] + outputs['skews'] = [float(s) for s in out['skews'].strip()] + outputs['average_scaling'] = float(out['avg_scaling'].strip()) + outputs['determinant'] = float(out['determinant'].strip()) + outputs['left_right_orientation_preserved'] = out['lr_orientation'].strip() == 'preserved' + outputs['forward_half_transform'] = [ + float(v) for v in r.split(' ') for r in out['fwd_half_xfm'].strip().split('\n')] + outputs['backward_half_transform'] = [ + float(v) for v in r.split(' ') for r in out['bwd_half_xfm'].strip().split('\n')] + + if self.inputs.all_param: + outputs['rot_angles'] = [float(r) for r in out['rot_angles'].strip().split(' ')] + outputs['translations'] = [float(r) for r in out['translations'].strip().split(' ')] return outputs From d4ac7baf6b4b826faaa711fb799e174570b8e227 Mon Sep 17 00:00:00 2001 From: oesteban Date: Thu, 4 Aug 2016 09:43:58 -0700 Subject: [PATCH 3/5] update specs --- nipype/interfaces/fsl/tests/test_auto_AvScale.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/nipype/interfaces/fsl/tests/test_auto_AvScale.py b/nipype/interfaces/fsl/tests/test_auto_AvScale.py index 0d750ddbc0..8d728e63b9 100644 --- a/nipype/interfaces/fsl/tests/test_auto_AvScale.py +++ b/nipype/interfaces/fsl/tests/test_auto_AvScale.py @@ -4,7 +4,9 @@ def test_AvScale_inputs(): - input_map = dict(args=dict(argstr='%s', + input_map = dict(all_param=dict(argstr='--allparams', + ), + args=dict(argstr='%s', ), environ=dict(nohash=True, usedefault=True, @@ -13,9 +15,12 @@ def test_AvScale_inputs(): usedefault=True, ), mat_file=dict(argstr='%s', - position=0, + position=-2, ), output_type=dict(), + ref_file=dict(argstr='%s', + position=-1, + ), terminal_output=dict(nohash=True, ), ) @@ -32,9 +37,11 @@ def test_AvScale_outputs(): determinant=dict(), forward_half_transform=dict(), left_right_orientation_preserved=dict(), + rot_angles=dict(), rotation_translation_matrix=dict(), scales=dict(), skews=dict(), + translations=dict(), ) outputs = AvScale.output_spec() From 649b212ef7155b279648871b6b90190943a9e6b1 Mon Sep 17 00:00:00 2001 From: oesteban Date: Thu, 4 Aug 2016 12:02:18 -0700 Subject: [PATCH 4/5] fix AvScale functionality --- nipype/interfaces/fsl/utils.py | 37 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/nipype/interfaces/fsl/utils.py b/nipype/interfaces/fsl/utils.py index 64f1b847d2..6dfbbfb327 100644 --- a/nipype/interfaces/fsl/utils.py +++ b/nipype/interfaces/fsl/utils.py @@ -22,6 +22,7 @@ import os import os.path as op +import re from glob import glob import warnings import tempfile @@ -608,7 +609,7 @@ def aggregate_outputs(self, runtime=None, needed_outputs=None): return outputs -class AvScaleInputSpec(FSLCommandInputSpec): +class AvScaleInputSpec(CommandLineInputSpec): all_param = traits.Bool(False, argstr='--allparams') mat_file = File(exists=True, argstr='%s', desc='mat file to read', position=-2) @@ -633,7 +634,7 @@ class AvScaleOutputSpec(TraitedSpec): translations = traits.List(traits.Float, desc='translations') -class AvScale(FSLCommand): +class AvScale(CommandLine): """Use FSL avscale command to extract info from mat file output of FLIRT Examples @@ -650,11 +651,9 @@ class AvScale(FSLCommand): _cmd = 'avscale' - def _format_arg(self, name, trait_spec, value): - return super(AvScale, self)._format_arg(name, trait_spec, value) + def _run_interface(self, runtime): + runtime = super(AvScale, self)._run_interface(runtime) - def aggregate_outputs(self, runtime=None, needed_outputs=None): - outputs = self._outputs() expr = re.compile( 'Rotation\ &\ Translation\ Matrix:\n(?P[0-9\.\ \n-]+)[\s\n]*' @@ -669,26 +668,30 @@ def aggregate_outputs(self, runtime=None, needed_outputs=None): '(?P[0-9\.\ \n-]+)[\s\n]*' 'Backward\ half\ transform\ =[\s]*\n' '(?P[0-9\.\ \n-]+)[\s\n]*') - out = expr.search(runtime.stdout).groupdict() - - outputs['rotation_translation_matrix'] = [ - float(v) for v in r.split(' ') for r in out['rot_tran_mat'].strip().split('\n')] - outputs['scales'] = [float(s) for s in out['scales'].strip()] - outputs['skews'] = [float(s) for s in out['skews'].strip()] + outputs = {} + outputs['rotation_translation_matrix'] = [[ + float(v) for v in r.strip().split(' ')] for r in out['rot_tran_mat'].strip().split('\n')] + outputs['scales'] = [float(s) for s in out['scales'].strip().split(' ')] + outputs['skews'] = [float(s) for s in out['skews'].strip().split(' ')] outputs['average_scaling'] = float(out['avg_scaling'].strip()) outputs['determinant'] = float(out['determinant'].strip()) outputs['left_right_orientation_preserved'] = out['lr_orientation'].strip() == 'preserved' - outputs['forward_half_transform'] = [ - float(v) for v in r.split(' ') for r in out['fwd_half_xfm'].strip().split('\n')] - outputs['backward_half_transform'] = [ - float(v) for v in r.split(' ') for r in out['bwd_half_xfm'].strip().split('\n')] + outputs['forward_half_transform'] = [[ + float(v) for v in r.strip().split(' ')] for r in out['fwd_half_xfm'].strip().split('\n')] + outputs['backward_half_transform'] = [[ + float(v) for v in r.strip().split(' ')] for r in out['bwd_half_xfm'].strip().split('\n')] if self.inputs.all_param: outputs['rot_angles'] = [float(r) for r in out['rot_angles'].strip().split(' ')] outputs['translations'] = [float(r) for r in out['translations'].strip().split(' ')] - return outputs + + setattr(self, '_results', outputs) + return runtime + + def _list_outputs(self): + return self._results class OverlayInputSpec(FSLCommandInputSpec): From 1f3626322949f9cabbcc518e0bd0a649f8ad296e Mon Sep 17 00:00:00 2001 From: oesteban Date: Thu, 4 Aug 2016 13:30:32 -0700 Subject: [PATCH 5/5] update CHANGES --- CHANGES | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index cb37e04467..950cc62d08 100644 --- a/CHANGES +++ b/CHANGES @@ -1,12 +1,18 @@ Upcoming release 0.13 ===================== +* ENH: Implement missing inputs/outputs in FSL AvScale + (https://github.com/nipy/nipype/pull/1563) + + Release 0.12.1 (August 3, 2016) -============================== +=============================== + * FIX: runtime profiling is optional and off by default (https://github.com/nipy/nipype/pull/1561) * TST: circle CI tests run with docker (https://github.com/nipy/nipype/pull/1541) * FIX: workflow export functions without import error (https://github.com/nipy/nipype/pull/1552) + Release 0.12.0 (July 12, 2016) ==============================