diff --git a/fsl/data/featimage.py b/fsl/data/featimage.py index 6c536ba109048b588ad1a9940563d61085c30027..a535ba92cfc20891164718280c053fe304433d8a 100644 --- a/fsl/data/featimage.py +++ b/fsl/data/featimage.py @@ -63,15 +63,14 @@ class FEATImage(fslimage.Image): ``<directory>.feat/filtered_func_data.nii.gz``. """ - featDir = featresults.getFEATDir(path) - - if featDir is None: - raise ValueError('{} does not appear to be data from a ' - 'FEAT analysis'.format(path)) - if op.isdir(path): - path = op.join(featDir, 'filtered_func_data') + path = op.join(path, 'filtered_func_data') + + if not featresults.isFEATImage(path): + raise ValueError('{} does not appear to be data ' + 'from a FEAT analysis'.format(path)) + featDir = op.dirname(path) settings = featresults.loadSettings( featDir) design = featresults.loadDesign( featDir) names, cons = featresults.loadContrasts(featDir) @@ -176,7 +175,7 @@ class FEATImage(fslimage.Image): if self.__pes[ev] is None: pefile = featresults.getPEFile(self.__featDir, ev) - self.__pes[ev] = FEATImage( + self.__pes[ev] = fslimage.Image( pefile, name='{}: PE{} ({})'.format( self.__analysisName, @@ -191,7 +190,7 @@ class FEATImage(fslimage.Image): if self.__residuals is None: resfile = featresults.getResidualFile(self.__featDir) - self.__residuals = FEATImage( + self.__residuals = fslimage.Image( resfile, name='{}: residuals'.format(self.__analysisName)) @@ -203,7 +202,7 @@ class FEATImage(fslimage.Image): if self.__copes[con] is None: copefile = featresults.getPEFile(self.__featDir, con) - self.__copes[con] = FEATImage( + self.__copes[con] = fslimage.Image( copefile, name='{}: COPE{} ({})'.format( self.__analysisName, @@ -220,7 +219,7 @@ class FEATImage(fslimage.Image): if self.__zstats[con] is None: zfile = featresults.getZStatFile(self.__featDir, con) - self.__zstats[con] = FEATImage( + self.__zstats[con] = fslimage.Image( zfile, name='{}: zstat{} ({})'.format( self.__analysisName, @@ -237,7 +236,7 @@ class FEATImage(fslimage.Image): if self.__clustMasks[con] is None: mfile = featresults.getClusterMaskFile(self.__featDir, con) - self.__clustMasks[con] = FEATImage( + self.__clustMasks[con] = fslimage.Image( mfile, name='{}: cluster mask for zstat{} ({})'.format( self.__analysisName, diff --git a/fsl/data/featresults.py b/fsl/data/featresults.py index 138c0379e11563504f39f4aac6ece0cb44db0036..5250788f65325f3762a46ecc9df442956e9c7915 100644 --- a/fsl/data/featresults.py +++ b/fsl/data/featresults.py @@ -13,8 +13,8 @@ following functions are provided: .. autosummary:: :nosignatures: + isFEATImage isFEATDir - getFEATDir hasMelodicDir loadDesign loadContrasts @@ -51,59 +51,48 @@ import fsl.utils.transform as transform log = logging.getLogger(__name__) -def isFEATDir(path): - """Returns ``True`` if the given path looks like a FEAT directory, or - looks like the input data for a FEAT analysis, ``False`` otherwise. - - :arg path: A file / directory path. +def isFEATImage(path): + """Returns ``True`` if the given path looks like it is the input data to + a FEAT analysis, ``False`` otherwise. """ + dirname = op.dirname( path) + filename = op.basename(path) - dirname, filename = op.split(path) + return filename.startswith('filtered_func_data') and isFEATDir(dirname) - featDir = getFEATDir(dirname) - isfeatdir = featDir is not None - - try: - hasdesfsf = op.exists(op.join(featDir, 'design.fsf')) - hasdesmat = op.exists(op.join(featDir, 'design.mat')) - hasdescon = op.exists(op.join(featDir, 'design.con')) - - isfeat = (isfeatdir and - hasdesmat and - hasdescon and - hasdesfsf) - - return isfeat - - except: - return False +def isFEATDir(path): + """Returns ``True`` if the given path looks like a FEAT directory, or + looks like the input data for a FEAT analysis, ``False`` otherwise. A + FEAT directory: -def getFEATDir(path): - """Given the path of any file/directory which is within a ``.feat`` or - ``.gfeat`` directory, strips all trailing components of the path name, - and returns the root FEAT directory. - - Returns ``None`` if the given path is not contained within a ``.feat`` - or ``.gfeat`` directory. + - Must be named ``*.feat``. + - Must contain a file called ``filtered_func_data.nii.gz``. + - Must contain a file called ``design.fsf``. + - Must contain a file called ``design.mat``. + - Must contain a file called ``design.con``. :arg path: A file / directory path. """ - sufs = ['.feat', '.gfeat'] - idxs = [(path.rfind(s), s) for s in sufs] - idx, suf = max(idxs, key=lambda (i, s): i) - - if idx == -1: - return None - - idx += len(suf) - path = path[:idx] + path = op.abspath(path) + + if op.isdir(path): dirname = path + else: dirname = op.dirname(path) + + if not dirname.endswith('.feat'): + return False - if path.endswith(suf) or path.endswith('{}{}'.format(suf, op.sep)): - return path - - return None + try: + fslimage.addExt(op.join(path, 'filtered_func_data'), mustExist=True) + except ValueError: + return False + + if not op.exists(op.join(dirname, 'design.fsf')): return False + if not op.exists(op.join(dirname, 'design.mat')): return False + if not op.exists(op.join(dirname, 'design.con')): return False + + return True def hasMelodicDir(featdir): diff --git a/fsl/data/melodicimage.py b/fsl/data/melodicimage.py index 7e3d7a0f2acee1e660a8e0be4de0ca59fd5d94d1..fd9772744611064de5dd9b37f09c27abfd7e1a6c 100644 --- a/fsl/data/melodicimage.py +++ b/fsl/data/melodicimage.py @@ -59,31 +59,18 @@ class MelodicImage(fslimage.Image): """ if op.isdir(path): - dirname = path - filename = 'melodic_IC' + path = op.join(path, 'melodic_IC') - else: - dirname = op.dirname( path) - filename = op.basename(path) - - dirname = dirname.rstrip(op.sep) - - if not melresults.isMelodicDir(dirname): + if not melresults.isMelodicImage(path): raise ValueError('{} does not appear to be a ' - 'MELODIC directory'.format(dirname)) - - if not filename.startswith('melodic_IC'): - raise ValueError('{} does not appear to be a MELODIC ' - 'component file'.format(filename)) + 'MELODIC component file'.format(path)) - fslimage.Image.__init__(self, - op.join(dirname, filename), - *args, - **kwargs) - - self.__meldir = dirname - self.__melmix = melresults.getComponentTimeSeries( dirname) - self.__melFTmix = melresults.getComponentPowerSpectra(dirname) + fslimage.Image.__init__(self, path, *args, **kwargs) + + meldir = op.dirname(path) + self.__meldir = meldir + self.__melmix = melresults.getComponentTimeSeries( meldir) + self.__melFTmix = melresults.getComponentPowerSpectra(meldir) self.__melICClass = melresults.MelodicClassification( self) # Automatically set the diff --git a/fsl/data/melodicresults.py b/fsl/data/melodicresults.py index 3b8d8dc33be34509741543a5957e873935898fc2..46e78a624a2ceec41a30836976907e3f2000e0cf 100644 --- a/fsl/data/melodicresults.py +++ b/fsl/data/melodicresults.py @@ -14,8 +14,8 @@ following functions are provided: .. autosummary:: :nosignatures: + isMelodicImage isMelodicDir - getMelodicDir getTopLevelAnalysisDir getDataFile getICFile @@ -38,62 +38,54 @@ import numpy as np import props -import fsl.data.image as fslimage -import fsl.data.featresults as featresults +import fsl.data.image as fslimage log = logging.getLogger(__name__) -def isMelodicDir(path): - """Returns ``True`` if the given path looks like it is contained within - a MELODIC directory, ``False`` otherwise. +def isMelodicImage(path): + """Returns ``True`` if the given path looks like it is a melodic + component image file, ``False`` otherwise. """ - # Must be named *.ica or *.gica - return getMelodicDir(path) is not None - -def getMelodicDir(path): - """Returns the MELODIC directory in which the given path is contained, - or ``None`` if it is not contained within a MELODIC directory. A melodic - directory: - - - Must be named ``*.ica`` or ``*.gica`` - - Must contain a file called ``melodic_IC.nii.gz`` - - Must contain a file called ``melodic_mix``. - """ + dirname = op.dirname( path) + filename = op.basename(path) - # TODO This code is identical to featresults.getFEATDir. - # Can you generalise it and put it somewhere in fsl.utils? - - path = op.abspath(path) + return filename.startswith('melodic_IC') and isMelodicDir(dirname) + - sufs = ['.ica', '.gica'] - idxs = [(path.rfind(s), s) for s in sufs] - idx, suf = max(idxs, key=lambda (i, s): i) +def isMelodicDir(path): + """Returns ``True`` if the given path looks like it is contained within + a MELODIC directory, ``False`` otherwise. A melodic directory: - if idx == -1: - return None + - Must be named ``*.ica``. + - Must contain a file called ``melodic_IC.nii.gz``. + - Must contain a file called ``melodic_mix``. + - Must contain a file called ``melodic_FTmix``. + """ - idx += len(suf) - path = path[:idx].rstrip(op.sep) + path = op.abspath(path) + + if op.isdir(path): dirname = path + else: dirname = op.dirname(path) - if not path.endswith(suf): - return None + if not dirname.endswith('.ica'): + return False # Must contain an image file called melodic_IC try: - fslimage.addExt(op.join(path, 'melodic_IC'), mustExist=True) + fslimage.addExt(op.join(dirname, 'melodic_IC'), mustExist=True) except ValueError: - return None + return False # Must contain files called # melodic_mix and melodic_FTmix - if not op.exists(op.join(path, 'melodic_mix')): return None - if not op.exists(op.join(path, 'melodic_FTmix')): return None - - return path + if not op.exists(op.join(dirname, 'melodic_mix')): return False + if not op.exists(op.join(dirname, 'melodic_FTmix')): return False + + return True def getTopLevelAnalysisDir(path): @@ -102,30 +94,24 @@ def getTopLevelAnalysisDir(path): directory is returned. Otherwise, ``None`` is returned. """ - meldir = getMelodicDir(path) - sufs = ['.feat', '.gfeat', '.ica', '.gica'] - - if meldir is None: - return None + path = path.strip() - if featresults.isFEATDir(meldir): - return featresults.getFEATDir(meldir) + # We've reached the root of the file system + if path == op.sep or path == '': + return None - parentDir = op.dirname(meldir) - parentDir = parentDir.rstrip(op.sep) + path = path.rstrip(op.sep) + parent = getTopLevelAnalysisDir(op.dirname(path)) - if not any([parentDir.endswith(s) for s in sufs]): - return None + if parent is not None: + return parent - # Must contain a file called filtered_func_data.nii.gz - dataFile = op.join(parentDir, 'filtered_func_data') + sufs = ['.ica', '.gica', '.feat', '.gfeat'] - try: - dataFile = fslimage.addExt(dataFile, mustExist=True) - except ValueError: - return None + if any([path.endswith(suf) for suf in sufs]): + return path - return parentDir + return None def getDataFile(meldir): diff --git a/fsl/fsleyes/overlay.py b/fsl/fsleyes/overlay.py index 053801d5f8db5d2e1667920a47045449a2a696af..1ede376e0f14418db55981c6f2431c992a9aac5a 100644 --- a/fsl/fsleyes/overlay.py +++ b/fsl/fsleyes/overlay.py @@ -204,37 +204,21 @@ def guessDataSourceType(path): if path.endswith('.vtk'): return fslmodel.Model, path - # Now, we check to see if the given - # path is part of a FEAT or MELODIC - # analysis. The way we go about this is - # a bit silly, but is necessary due to - # the fact thet a melodic analysis can - # be contained within a feat analysis - # (or another melodic analysis). So we - # check for all analysis types and, if - # more than one analysis type matches, - # we return the one with the longest - # path name. - analyses = [ - (fslfeatimage.FEATImage, featresults.getFEATDir( path)), - (fslmelimage .MelodicImage, melresults .getMelodicDir(path))] - - # Remove the analysis types that didn't match - # (the get*Dir function returned None) - analyses = [(t, d) for (t, d) in analyses if d is not None] - - # If we have one or more matches for - # an analysis directory, we return - # the one with the longest path - if len(analyses) > 0: - - dirlens = map(len, [d for (t, d) in analyses]) - maxidx = dirlens.index(max(dirlens)) - - return analyses[maxidx] - # If the path is not an analysis directory, - # see if it is a regular nifti image + if op.isdir(path): + if melresults.isMelodicDir(path): + return fslmelimage.MelodicImage, path + + if featresults.isFEATDir(path): + return fslfeatimage.FEATImage, path + + elif melresults.isMelodicImage(path): + return fslmelimage.MelodicImage, path + + elif featresults.isFEATImage(path): + return fslfeatimage.FEATImage, path + + # A regular NIFTI image? try: path = fslimage.addExt(path, mustExist=True) return fslimage.Image, path