2020 AFNICommandOutputSpec , AFNIPythonCommandInputSpec ,
2121 AFNIPythonCommand , Info , no_afni )
2222
23+ from ...import logging
24+ iflogger = logging .getLogger ('nipype.interface' )
25+
2326
2427class CentralityInputSpec (AFNICommandInputSpec ):
2528 """Common input spec class for all centrality-related commands
@@ -2565,9 +2568,10 @@ class TProject(AFNICommand):
25652568 output_spec = AFNICommandOutputSpec
25662569
25672570
2571+
25682572class TShiftInputSpec (AFNICommandInputSpec ):
25692573 in_file = File (
2570- desc = 'input file to 3dTShift ' ,
2574+ desc = 'input file to 3dTshift ' ,
25712575 argstr = '%s' ,
25722576 position = - 1 ,
25732577 mandatory = True ,
@@ -2594,12 +2598,26 @@ class TShiftInputSpec(AFNICommandInputSpec):
25942598 desc = 'ignore the first set of points specified' , argstr = '-ignore %s' )
25952599 interp = traits .Enum (
25962600 ('Fourier' , 'linear' , 'cubic' , 'quintic' , 'heptic' ),
2597- desc = 'different interpolation methods (see 3dTShift for details) '
2601+ desc = 'different interpolation methods (see 3dTshift for details) '
25982602 'default = Fourier' ,
25992603 argstr = '-%s' )
2600- tpattern = Str (
2604+ tpattern = traits .Either (
2605+ traits .Enum ('alt+z' , 'altplus' , # Synonyms
2606+ 'alt+z2' ,
2607+ 'alt-z' , 'altminus' , # Synonyms
2608+ 'alt-z2' ,
2609+ 'seq+z' , 'seqplus' , # Synonyms
2610+ 'seq-z' , 'seqminus' ), # Synonyms
2611+ Str , # For backwards compatibility
26012612 desc = 'use specified slice time pattern rather than one in header' ,
2602- argstr = '-tpattern %s' )
2613+ argstr = '-tpattern %s' ,
2614+ xor = ['slice_timing' ])
2615+ slice_timing = traits .Either (
2616+ File (exists = True ),
2617+ traits .List (traits .Float ),
2618+ desc = 'time offsets from the volume acquisition onset for each slice' ,
2619+ argstr = '-tpattern @%s' ,
2620+ xor = ['tpattern' ])
26032621 rlt = traits .Bool (
26042622 desc = 'Before shifting, remove the mean and linear trend' ,
26052623 argstr = '-rlt' )
@@ -2609,6 +2627,10 @@ class TShiftInputSpec(AFNICommandInputSpec):
26092627 argstr = '-rlt+' )
26102628
26112629
2630+ class TShiftOutputSpec (AFNICommandOutputSpec ):
2631+ timing_file = File (desc = "AFNI formatted timing file, if ``slice_timing`` is a list" )
2632+
2633+
26122634class TShift (AFNICommand ):
26132635 """Shifts voxel time series from input so that seperate slices are aligned
26142636 to the same temporal origin.
@@ -2619,19 +2641,101 @@ class TShift(AFNICommand):
26192641 Examples
26202642 ========
26212643
2644+ Slice timing details may be specified explicitly via the ``slice_timing``
2645+ input:
2646+
26222647 >>> from nipype.interfaces import afni
2648+ >>> TR = 2.5
2649+ >>> tshift = afni.TShift()
2650+ >>> tshift.inputs.in_file = 'functional.nii'
2651+ >>> tshift.inputs.tzero = 0.0
2652+ >>> tshift.inputs.tr = '%.1fs' % TR
2653+ >>> tshift.inputs.slice_timing = list(np.arange(40) / TR)
2654+ >>> tshift.cmdline
2655+ '3dTshift -prefix functional_tshift -tpattern @slice_timing.1D -TR 2.5s -tzero 0.0 functional.nii'
2656+
2657+ When the ``slice_timing`` input is used, the ``timing_file`` output is populated,
2658+ in this case with the generated file.
2659+
2660+ >>> tshift._list_outputs()['timing_file'] # doctest: +ELLIPSIS
2661+ '.../slice_timing.1D'
2662+
2663+ This method creates a ``slice_timing.1D`` file to be passed to ``3dTshift``.
2664+ A pre-existing slice-timing file may be used in the same way:
2665+
2666+ >>> tshift = afni.TShift()
2667+ >>> tshift.inputs.in_file = 'functional.nii'
2668+ >>> tshift.inputs.tzero = 0.0
2669+ >>> tshift.inputs.tr = '%.1fs' % TR
2670+ >>> tshift.inputs.slice_timing = 'slice_timing.1D'
2671+ >>> tshift.cmdline
2672+ '3dTshift -prefix functional_tshift -tpattern @slice_timing.1D -TR 2.5s -tzero 0.0 functional.nii'
2673+
2674+ When a pre-existing file is provided, ``timing_file`` is simply passed through.
2675+
2676+ >>> tshift._list_outputs()['timing_file'] # doctest: +ELLIPSIS
2677+ '.../slice_timing.1D'
2678+
2679+ Alternatively, pre-specified slice timing patterns may be specified with the
2680+ ``tpattern`` input.
2681+ For example, to specify an alternating, ascending slice timing pattern:
2682+
26232683 >>> tshift = afni.TShift()
26242684 >>> tshift.inputs.in_file = 'functional.nii'
2685+ >>> tshift.inputs.tzero = 0.0
2686+ >>> tshift.inputs.tr = '%.1fs' % TR
26252687 >>> tshift.inputs.tpattern = 'alt+z'
2688+ >>> tshift.cmdline
2689+ '3dTshift -prefix functional_tshift -tpattern alt+z -TR 2.5s -tzero 0.0 functional.nii'
2690+
2691+ For backwards compatibility, ``tpattern`` may also take filenames prefixed
2692+ with ``@``.
2693+ However, in this case, filenames are not validated, so this usage will be
2694+ deprecated in future versions of Nipype.
2695+
2696+ >>> tshift = afni.TShift()
2697+ >>> tshift.inputs.in_file = 'functional.nii'
26262698 >>> tshift.inputs.tzero = 0.0
2699+ >>> tshift.inputs.tr = '%.1fs' % TR
2700+ >>> tshift.inputs.tpattern = '@slice_timing.1D'
26272701 >>> tshift.cmdline
2628- '3dTshift -prefix functional_tshift -tpattern alt+z -tzero 0.0 functional.nii'
2629- >>> res = tshift.run() # doctest: +SKIP
2702+ '3dTshift -prefix functional_tshift -tpattern @slice_timing.1D -TR 2.5s -tzero 0.0 functional.nii'
2703+
2704+ In these cases, ``timing_file`` is undefined.
26302705
2706+ >>> tshift._list_outputs()['timing_file'] # doctest: +ELLIPSIS
2707+ <undefined>
2708+
2709+ In any configuration, the interface may be run as usual:
2710+
2711+ >>> res = tshift.run() # doctest: +SKIP
26312712 """
26322713 _cmd = '3dTshift'
26332714 input_spec = TShiftInputSpec
2634- output_spec = AFNICommandOutputSpec
2715+ output_spec = TShiftOutputSpec
2716+
2717+ def _format_arg (self , name , trait_spec , value ):
2718+ if name == 'tpattern' and value .startswith ('@' ):
2719+ iflogger .warning ('Passing a file prefixed by "@" will be deprecated'
2720+ '; please use the `slice_timing` input' )
2721+ elif name == 'slice_timing' and isinstance (value , list ):
2722+ value = self ._write_slice_timing ()
2723+ return super (TShift , self )._format_arg (name , trait_spec , value )
2724+
2725+ def _write_slice_timing (self ):
2726+ fname = 'slice_timing.1D'
2727+ with open (fname , 'w' ) as fobj :
2728+ fobj .write ('\t ' .join (map (str , self .inputs .slice_timing )))
2729+ return fname
2730+
2731+ def _list_outputs (self ):
2732+ outputs = super (TShift , self )._list_outputs ()
2733+ if isdefined (self .inputs .slice_timing ):
2734+ if isinstance (self .inputs .slice_timing , list ):
2735+ outputs ['timing_file' ] = os .path .abspath ('slice_timing.1D' )
2736+ else :
2737+ outputs ['timing_file' ] = os .path .abspath (self .inputs .slice_timing )
2738+ return outputs
26352739
26362740
26372741class VolregInputSpec (AFNICommandInputSpec ):
0 commit comments