-
Notifications
You must be signed in to change notification settings - Fork 533
enh: trait for imaging files + implementation in SPM preproc #1949
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1949 +/- ##
=========================================
+ Coverage 72.29% 72.3% +0.01%
=========================================
Files 1089 1089
Lines 55586 55626 +40
Branches 8010 8017 +7
=========================================
+ Hits 40184 40223 +39
- Misses 14148 14149 +1
Partials 1254 1254
Continue to review full report at Codecov.
|
nipype/interfaces/spm/preprocess.py
Outdated
raise TypeError('Input files must be uncompressed') | ||
else: | ||
if is_gz(self.inputs.in_files): | ||
raise TypeError('Input files must be uncompressed') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if there's a better approach in general, but the test can be made much more concise:
if isdefined(self.inputs.in_files) and any(imgf.endswith('.gz')
for imgf in filename_to_list(self.inputs.in_files)):
raise TypeError('Input files must be uncompressed')
i think this is a good place to start writing a new traits also SPM can accept list of lists of 3D files so the check in this PR has to account for those scenarios. this is another reason to write a new Trait. |
@satra maybe something like this? only in this case, file endings are checked instead of types - any recommendation for that? class ImageFile(File):
""" Defines a trait of specific neuroimaging files """
def __init__(self, value='', filter=None, auto_set=False, entries=0,
exists=False, types=[], compressed=True, **metadata):
""" Trait handles neuroimaging files.
Parameters
----------
types : list
The accepted file-types
compressed : boolean
Indicates whether the file-type can compressed
"""
self.types = types
self.compressed = compressed
super(ImageFile, self).__init__(value, filter, auto_set, entries, exists, **metadata)
def validate(self, object, name, value):
""" Validates that a specified value is valid for this trait.
"""
validated_value = super(ImageFile, self).validate(object, name, value)
if validated_value and self.types:
if self.compressed:
self.types.extend([x + '.gz' for x in self.types])
if not any(validated_value.endswith(x) for x in self.types):
raise TraitError(
args="{} is not included in allowed types: {}".format(
validated_value, ','.join(self.types)))
return validated_value |
validated_value = super(ImageFile, self).validate(object, name, value) | ||
if validated_value and self.types: | ||
if self.compressed: | ||
self.types.extend([x + '.gz' for x in self.types]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how would this handle mgz
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that case would have to added into types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgxd - are you planning to fix this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, i'll revisit it today
""" Validates that a specified value is valid for this trait. | ||
""" | ||
validated_value = super(ImageFile, self).validate(object, name, value) | ||
if validated_value and self.types: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you check if self.types
always returns True
even if the metadata is not there? in the past traits would some weird things like that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah - if types
is defined as an empty list, it'll return False
""" Defines a trait of specific neuroimaging files """ | ||
|
||
def __init__(self, value='', filter=None, auto_set=False, entries=0, | ||
exists=False, types=['nii', 'hdr', 'img'], compressed=True, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the reason i would suggest going with file format types instead of extensions is that programs that accept nifti-1 may not be able to run with nifti-2.
so here is an incomplete list: http://www.reproducibleimaging.org/module-dataprocessing/03-data/ (see mri data section)
and here is a description of nifti-1 vs nifti-2 check for future reference (i don't want to implement all validators right now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
link to nifti1 vs nifti2?
maybe we can work around this by adding a field to ImageFile
that specifies format_version
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
say one of the other interfaces (e.g., dcm2niix) were to restrict input files to dicoms. how would you determine that the input was valid for the MGH dicoms for example, which don't have extensions?
i'm also thinking of how we can use this interface to auto-(un)compress eventually instead of restricting it.
further compressed nifti pair would involve img/hdr.gz pairs. if we check only the header, then spm could still run into trouble.
so types can be format with details about compressed and uncompressed being something like this to start with:
{'nifti1': [('.nii', '.nii.gz'), (('.hdr', '.img'), ('.hdr', '.img.gz'))],
'mgh': [('.mgh', '.mgz')],
...
}
at least for now, since this solution is focused on spm, let's use Nifti1 as the type and check for the various combinations listed above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gllmflndn: does spm now support nifti-2?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SPM12 should read NIfTI-2 files - I don't think it has been used much yet though.
Since you are working on this new trait, I have a thought since long ago about the File trait. This could be a good PR for it. Can we please change the messages when the trait validation fails?
|
# each element consists of : | ||
# - uncompressed (tuple[0]) extension | ||
# - compressed (tuple[1]) extension | ||
img_fmt_types = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@satra I haven't included validation yet, but LMKWYT
if fmt in img_fmt_types: | ||
exts.extend(sum([[u for u in y[0]] if isinstance(y[0], tuple) | ||
else [y[0]] for y in img_fmt_types[fmt]], [])) | ||
if self.compressed: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compressed=True
should allow for compressed and normal. perhaps we should change compressed
to allow_compressed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it does - it will extend on the normal
'nifti2': [('.nii', '.nii.gz'), | ||
(('.hdr', '.img'), ('.hdr', '.img.gz'))], | ||
'cifti2': [('.nii', '.nii.gz'), | ||
(('.hdr', '.img'), ('.hdr', '.img.gz'))], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cifti doesn't allow hdr-img i think - can you check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like not supported in nifti2 or cifti2. also should img/hdr be separated as it's own ANALYZE format?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i don't think we should support analyze :)
@mgxd - looks good. the new traits need some tests. |
exists, **metadata) | ||
|
||
def grab_exts(self): | ||
# TODO: file type validation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mgxd : are you still planning to add something more to this validation? or should I remove TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now we are only checking the extensions, but in the future it would be nice to check bit differences (like say between nifti1 and nifti2)
should be extended to the other spm interfaces - is there a better way to approach this?
also updated some missed auto-tests