Creating outputs on the fly from python script

Hi all,

I have a python script that genreates the outputs AIF_ROI and aif_plot.

aif_plot is a PNG-file and could be either one file or up to 4 separet files.where n could be 1 or up to four.

The question is how i get the nipype wrapper to handle a list of outputs from the output aif_plot.

Here’s some of the code:

class aifCalcInputSpec(BaseInterfaceInputSpec):
    conc_file = File(exists=True, desc='4D volume from where concentration curves are extracted', mandatory=True)
    peakconc_file = File(exists=True, desc='3D volume whcich are used for displaying cluster result etc', mandatory=True)
    brain_mask =  File(exists=True, desc='Brain mask for the concentration data', mandatory=True)
    ROI_file =  File(exists=True, desc='The ROI from where the AIF is calculated', mandatory=True)
    ireg_feat =  File(exists=True, desc='Ireg feature for the data', mandatory=True)
    auc_feat =  File(exists=True, desc='AUC feature for the data', mandatory=True)
    firstM_feat =  File(exists=True, desc='First moment feature for the data', mandatory=True)
    variables =  File(exists=True, desc='The variables file containing baseline index', mandatory=True)

class aifCalcOutputSpec(TraitedSpec):
    aif_ROI = File(exists=True, desc="The AIF ROI i 3D")
    aif_plot = File(exists=True, desc="A plot for QA")
    
    
class aifCalc(BaseInterface):
    input_spec = aifCalcInputSpec
    output_spec = aifCalcOutputSpec

    def _run_interface(self, runtime):
        
        ----CALCULATIONS------

         nib.save(AIF_img, 'AIF_ROI.nii')
           
           # Checking if it's one or several PNG file that should be saved
           if len(unique_slices) > 1:
                fileName = 'AIF_result' + str(n+1)
           else: 
                fileName = 'AIF_result' 
           figure[0].savefig(fileName, dpi =300)
           figure[0].clf()
           plt.close(figure[0])
           
           roiCalc = roiCalc + 1
           
           return runtime

def _list_outputs(self):
    outputs = self._outputs().get()

    #Here's my own solutions but it doesnt work
    aifResult_list = []
    for f in os.listdir():
         if f.startswith('AIF_result'):
              aifResult_list.append(os.path.abspath(f))

    outputs["aif_ROI"] = os.path.abspath('AIF_ROI.nii')
    outputs["aif_plot"] = aifResult_list

    return outputs

From this code I’m getting the error

FileNotFoundError: No such file or directory '['/home/brain/Documents/inph/test/registration/AIF_result1.png']' for output 'aif_plot' of a aifCalc interface

Appreciate any help!

Hi @jesperbrowall !

I think the issue is that when defining the aifCalcOutputSpec class you are setting the aif_plot attribute to expect a single file, not a list of files (even if that list only has one file!). You could try modifying the class definition to:

class aifCalcOutputSpec(TraitedSpec):
    aif_ROI = File(exists=True, desc="The AIF ROI i 3D")
    aif_plot = List(File(exists=True, desc="A plot for QA")) 

(Note that aif_plot is being set to List(File) here instead of just File.)

Hope that helps!
Ross

Hi @rmarkello!

Couldn’t import just List but

traits.List(File(exists=True, desc="A plot for QA")) certainly did the job. I also realized that I had an indentation error in return runtime. Now it runs perfectly!

Thank you!

1 Like

Hi again!

Kinda similiar problem now, and that is to have a list of ROI-files as input. I use MapNode to get this list of inputs.

Here’s the script: (Note that it’s the float_file that is the list of inputs)

class reg_ResampleInputSpec(BaseInterfaceInputSpec):
    ref_file = File(exists=True, desc='Reference volume', mandatory=True)
    float_file = traits.List(File(exists=True, desc='Floating volume', mandatory=True))
    trans_file = File(exists=True, desc='Affine transformation matrix', mandatory=True)

   class reg_ResampleOutputSpec(TraitedSpec):
       out_file = traits.List(File(exists=True, desc="Resulting file in ref_file fram of reference"))

   class reg_Resample(BaseInterface):
       input_spec = reg_ResampleInputSpec
       output_spec = reg_ResampleOutputSpec

       def _run_interface(self, runtime):
           ref_fileName = self.inputs.ref_file
           float_fileName = self.inputs.float_file
           trans_fileName = self.inputs.trans_file

           output_fileName = split_filename(trans_fileName)[1]+ '.nii'
    
           term_comand = 'reg_resample ' + '-ref ' + ref_fileName + ' -flo ' + float_fileName + ' -aff ' + output_fileName+ \
               ' -res ' + output_fileName + '.nii ' + '-LIN'
           os.system(term_comand)

           return runtime

       def _list_outputs(self):
           outputs = self._outputs().get()
           trans_fileName = self.inputs.trans_file
           output_fileName = split_filename(trans_fileName)[1]+ '.nii'
           outputs["out_file"] = os.path.abspath(output_fileName)

           return outputs

This is the error from Jupyter:

trait of a reg_ResampleInputSpec instance must be a pathlike object or string representing an existing file, but a value of "[\'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/NAWMdx.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/NAWMsin.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/PVWMantdx.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/PVWMantsin.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/PVWMpostdx.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/PVWMpostsin.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/aif_sin_overseg.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/cauddx.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/caudsin.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/lentdx.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/lentsin.nii\', \'/media/mrfysik/iNPH/jesper/ROI/sub-43_ses-1/ROIinFLAIR/thalcentdx.ni..........

Hi @jesperbrowall !

It’s tough to say without the full traceback of the error… A few shots-in-the-dark:

  1. Somehow your list of files is getting passed to the float_file trait as a string, rather than a list of strings / paths.
  2. The error is coming from one of the other traits in the class?

Let me know if either of those seem feasible; if not, any more info about either the code you’re running or the error would be awesome!

Slightly different topic: I think you should check the out_file trait of your reg_ResampleOutputSpec. It looks like out_file is supposed to be a list of files but you’re assigning it just a single file in the _list_outputs() method. I might be misinterpreting that, though, so let me know!

Hi @rmarkello! Thank you for taking your time for this.

Ok so (1) was completely right and same with that out_file should be a list of outputs. The error is now somewhat different and I’m gonna try to give you as much relevant information as possible.

Here’s the relevant code that calls for the self written function: (ROI_files is a list of files)

inputnode_trans = Node(IdentityInterface(fields=['ROI_files', 't2star_trans_matrix', 't2star',
                                                'adc_trans_matrix', 'adcmap']), name='inputnode')

resample_node = Node(reg_Resample(), name = 'Transform')


thresh_node = MapNode(maths.Threshold(), name="Threshold", iterfield=['in_file'])
thresh_node.inputs.thresh = 0.5

bin_node = MapNode(maths.UnaryMaths(), name="Binary", iterfield=['in_file'])
bin_node.inputs.operation = 'bin'

# Output node
outputnode_trans = Node(IdentityInterface(fields=['ROI_files_t2star', 'ROI_files_adcmap']), name='outputnode')

# Connect workflow
wf_trans = Workflow(name='ROI_Transformation', base_dir= output_dir )
wf_trans.connect([(inputnode_trans, resample_node,[('ROI_files','float_file'),
                                                       ('t2star_trans_matrix', 'trans_file'),
                                                       ('t2star','ref_file')]),
                  (resample_node, thresh_node,[('out_file','in_file')]),
                  (thresh_node, bin_node,[('out_file','in_file')]),
                  (bin_node, outputnode_trans,[('out_file','ROI_files_t2star')]),
                ])

Here’s the code of reg_resample:

from nipype.interfaces.base import BaseInterface, \
    BaseInterfaceInputSpec, traits, File, TraitedSpec
from nipype.interfaces.io import  DataSink
from nipype.utils.filemanip import split_filename
from nipype import Workflow, Node
import os
import numpy as np
import nibabel as nib

class reg_ResampleInputSpec(BaseInterfaceInputSpec):
    ref_file = File(exists=True, desc='Reference volume', mandatory=True)
    float_file = traits.List(File(exists=True, desc='Floating volume', mandatory=True))
    trans_file = File(exists=True, desc='Affine transformation matrix', mandatory=True)

class reg_ResampleOutputSpec(TraitedSpec):
    out_file = traits.List(File(exists=True, desc="Resulting file in ref_file fram of reference"))

class reg_Resample(BaseInterface):
    input_spec = reg_ResampleInputSpec
    output_spec = reg_ResampleOutputSpec

    def _run_interface(self, runtime):
        ref_fileName = self.inputs.ref_file
        float_fileName = self.inputs.float_file
        trans_fileName = self.inputs.trans_file
    
        for name in float_fileName:

           output_fileName = split_filename(name)[1] + '.nii'
    
           term_comand = 'reg_resample ' + '-ref ' + ref_fileName + ' -flo ' + name + ' -aff ' + trans_fileName+ \
            ' -res ' + output_fileName + ' -LIN'
           os.system(term_comand)

           return runtime
    
    def _list_outputs(self):
        outputs = self._outputs().get()

        float_fileName = self.inputs.float_file
        out_fileList = []
        for name in float_fileName:
           output_fileName = split_filename(name)[1] + '.nii'
           out_fileList.append(os.path.abspath(output_fileName))

        outputs["out_file"] = out_fileList

        return outputs

Here’s the error message:

No such file or directory '['/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/NAWMdx.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/NAWMsin.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/PVWMantdx.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/PVWMantsin.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/PVWMpostdx.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/PVWMpostsin.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/aif_sin_overseg.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/cauddx.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/caudsin.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/lentdx.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/lentsin.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/shamsin.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/thalcentdx.nii', '/media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/thalcentsin.nii']' for output 'out_file' of a reg_Resample interface\n"]}

just to verify, does this file actually exist when you receive the error?

Hi @satra!

No it doesn’t. But this file does exist: /media/mrfysik/iNPH/jesper/inph_workflow_pt2/studieproc/patproc/ROI_Transformation/_session_id_2_subject_id_43/Transform/NAWMdx.nii

Solved!
I let the MapNode walk through the list of inputs letting reg_ResampleInputSpec and reg_ResampleOutpuSpec only treat files and not lists.

inputnode_trans = Node(IdentityInterface(fields=['ROI_files', 't2star_trans_matrix', 't2star',
                                                'adc_trans_matrix', 'adcmap']), name='inputnode')

resample_node = **MapNode**(reg_Resample(), name = 'Transform')


thresh_node = MapNode(maths.Threshold(), name="Threshold", iterfield=['in_file'])
thresh_node.inputs.thresh = 0.5

bin_node = MapNode(maths.UnaryMaths(), name="Binary", iterfield=['in_file'])
bin_node.inputs.operation = 'bin'

# Output node
outputnode_trans = Node(IdentityInterface(fields=['ROI_files_t2star', 'ROI_files_adcmap']), name='outputnode')

# Connect workflow
wf_trans = Workflow(name='ROI_Transformation', base_dir= output_dir )
wf_trans.connect([(inputnode_trans, resample_node,[('ROI_files','float_file'),
                                                       ('t2star_trans_matrix', 'trans_file'),
                                                       ('t2star','ref_file')]),
                  (resample_node, thresh_node,[('out_file','in_file')]),
                  (thresh_node, bin_node,[('out_file','in_file')]),
                  (bin_node, outputnode_trans,[('out_file','ROI_files_t2star')]),
                ])
from nipype.interfaces.base import BaseInterface, \
    BaseInterfaceInputSpec, traits, File, TraitedSpec
from nipype.interfaces.io import  DataSink
from nipype.utils.filemanip import split_filename
from nipype import Workflow, Node
import os
import numpy as np
import nibabel as nib

class reg_ResampleInputSpec(BaseInterfaceInputSpec):
    ref_file = File(exists=True, desc='Reference volume', mandatory=True)
    float_file = File(exists=True, desc='Floating volume', mandatory=True)
    trans_file = File(exists=True, desc='Affine transformation matrix', mandatory=True)

class reg_ResampleOutputSpec(TraitedSpec):
    out_file = File(exists=True, desc="Resulting file in ref_file fram of reference")
class reg_Resample(BaseInterface):
    input_spec = reg_ResampleInputSpec
    output_spec = reg_ResampleOutputSpec

    def _run_interface(self, runtime):
        ref_fileName = self.inputs.ref_file
        float_fileName = self.inputs.float_file
        trans_fileName = self.inputs.trans_file

        output_fileName = split_filename(float_fileName)[1] + '.nii'

        term_comand = 'reg_resample ' + '-ref ' + ref_fileName + ' -flo ' + float_fileName + ' -aff ' + trans_fileName+ \
        ' -res ' + output_fileName + ' -LIN'
        os.system(term_comand)

        return runtime
    
    def _list_outputs(self):
        outputs = self._outputs().get()
        float_fileName = self.inputs.float_file
        output_fileName = split_filename(float_fileName)[1] + '.nii'
        outputs["out_file"] = os.path.abspath(output_fileName)
        return outputs
1 Like