Skip to content
Snippets Groups Projects
Commit 0918a269 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

Documentation for melodicimage and melodicresults modules. MelodicImage

now automatically sets a TR property, if it can find the data
file. TimeSeries scales melodic time series by this TR accordingly.
parent ab5f3a47
No related branches found
No related tags found
No related merge requests found
......@@ -8,30 +8,57 @@
"""This module provides the :class:`MelodicImage` class, an :class:`.Image`
sub-class which encapsulates data from a MELODIC analysis.
"""
import os.path as op
import props
import image as fslimage
import melodicresults as melresults
class MelodicImage(fslimage.Image):
"""The ``MelodicImage`` class is an :class:`.Image` which encapsulates
the results of a FSL MELODIC analysis. A ``MelodicImage`` corresponds to
the spatial component map file, generally called ``melodic_IC.nii.gz``.
The ``MelodicImage`` class provides a few MELODIC-specific attributes and
methods:
.. autosummary::
tr
getComponentTimeSeries
numComponents
getDataFile
"""
tr = props.Real(default=1.0)
"""The TR time of the raw data from which this ``MelodicImage`` was
generated. If it is possible to do so, this is automatically initialised
from the data file (see the :meth:`getDataFile` method).
"""
def __init__(self, image, *args, **kwargs):
"""
"""
def __init__(self, path, *args, **kwargs):
"""Create a ``MelodicImage``.
:arg path: A path specifying the ``melodic_IC`` image file, or the
``.ica`` directory.
if op.isdir(image):
All other arguments are passed through to the :meth:`.Image.__init__`
method.
"""
dirname = image
if op.isdir(path):
dirname = path
filename = 'melodic_IC'
else:
dirname = op.dirname( image)
filename = op.basename(image)
dirname = op.dirname( path)
filename = op.basename(path)
dirname = dirname.rstrip(op.sep)
......@@ -48,12 +75,32 @@ class MelodicImage(fslimage.Image):
*args,
**kwargs)
self.__meldir = dirname
self.__melmix = melresults.getComponentTimeSeries(dirname)
# Automatically set the
# TR value if possible
dataFile = self.getDataFile()
if dataFile is not None:
dataImage = fslimage.Image(dataFile, loadData=False)
if dataImage.is4DImage():
self.tr = dataImage.pixdim[3]
def getComponentTimeSeries(self, component):
"""Returns the time course for the specified (0-indexed) component. """
return self.__melmix[:, component]
def numComponents(self):
"""Returns the number of components in this ``MelodicImage``. """
return self.shape[3]
def getDataFile(self):
"""Returns the file name of the data image from which this
``MelodicImage`` was generated, if possible. See the
:func:`.melodicresults.getDataFile` function.
"""
return melresults.getDataFile(self.__meldir)
......@@ -15,49 +15,46 @@ following functions are provided:
isMelodicDir
getMelodicDir
getTopLevelAnalysisDir
getDataFile
getICFile
getMixFile
getNumComponents
getComponentTimeSeries
"""
import os
import os.path as op
import numpy as np
import fsl.data.image as fslimage
import fsl.data.image as fslimage
import fsl.data.featresults as featresults
def isMelodicDir(path):
"""
"""Returns ``True`` if the given path looks like it is contained within
a MELODIC directory, ``False`` otherwise.
"""
# Must be named *.ica or *.gica
meldir = getMelodicDir(path)
if meldir is None:
return False
# Must contain an image file called melodic_IC
try:
fslimage.addExt(op.join(meldir, 'melodic_IC'), mustExist=True)
except ValueError:
return False
# Must contain a file called melodic_mix
if not op.exists(op.join(meldir, 'melodic_mix')):
return False
return True
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``.
"""
# TODO This code is identical to featresults.getFEATDir.
# Can you generalise it and put it somewhere in fsl.utils?
path = op.abspath(path)
sufs = ['.ica', '.gica']
idxs = [(path.rfind(s), s) for s in sufs]
idx, suf = max(idxs, key=lambda (i, s): i)
......@@ -66,28 +63,88 @@ def getMelodicDir(path):
return None
idx += len(suf)
path = path[:idx]
path = path[:idx].rstrip(op.sep)
if path.endswith(suf) or path.endswith('{}{}'.format(suf, op.sep)):
return path
if not path.endswith(suf):
return None
# Must contain an image file called melodic_IC
try:
fslimage.addExt(op.join(path, 'melodic_IC'), mustExist=True)
except ValueError:
return None
# Must contain a file called melodic_mix
if not op.exists(op.join(path, 'melodic_mix')):
return None
return None
return path
def getICFile(meldir):
def getTopLevelAnalysisDir(path):
"""If the given path is a MELODIC directory, and it is contained within
a FEAT directory, or another MELODIC directory, the path to the latter
directory is returned. Otherwise, ``None`` is returned.
"""
meldir = getMelodicDir(path)
sufs = ['.feat', '.gfeat', '.ica', '.gica']
if meldir is None:
return None
if featresults.isFEATDir(meldir):
return featresults.getFEATDir(meldir)
parentDir = op.dirname(meldir)
parentDir = parentDir.rstrip(op.sep)
if not any([parentDir.endswith(s) for s in sufs]):
return None
# Must contain a file called filtered_func_data.nii.gz
dataFile = op.join(parentDir, 'filtered_func_data')
try:
dataFile = fslimage.addExt(dataFile, mustExist=True)
except ValueError:
return None
return parentDir
def getDataFile(meldir):
"""If the given melodic directory is contained within another analysis
directory, the path to the data file is returned. Otherwise ``None`` is
returned.
"""
topDir = getTopLevelAnalysisDir(meldir)
if topDir is None:
return None
dataFile = op.join(topDir, 'filtered_func_data')
try:
return fslimage.addExt(dataFile, mustExist=True)
except ValueError:
return None
def getICFile(meldir):
"""Returns the path to the melodic IC image. """
return fslimage.addExt(op.join(meldir, 'melodic_IC'))
def getMixFile(meldir):
"""
"""
"""Returns the path to the melodic mix file. """
return op.join(meldir, 'melodic_mix')
def getNumComponents(meldir):
"""
"""Returns the number of components generated in the melodic analysis
contained in the given directrory.
"""
icImg = fslimage.Image(getICFile(meldir), loadData=False)
......@@ -95,7 +152,8 @@ def getNumComponents(meldir):
def getComponentTimeSeries(meldir):
"""
"""Returns a ``numpy`` array containing the melodic mix for the given
directory.
"""
mixfile = getMixFile(meldir)
......
......@@ -26,8 +26,9 @@ import numpy as np
import props
import dataseries
import fsl.data.strings as strings
import dataseries
import fsl.data.strings as strings
import fsl.data.melodicimage as fslmelimage
class TimeSeries(dataseries.DataSeries):
......@@ -90,7 +91,10 @@ class TimeSeries(dataseries.DataSeries):
ydata = np.array(ydata, dtype=np.float32)
if self.tsPanel.usePixdim:
xdata *= self.overlay.pixdim[3]
if isinstance(self.overlay, fslmelimage.MelodicImage):
xdata *= self.overlay.tr
else:
xdata *= self.overlay.pixdim[3]
if self.tsPanel.plotMode == 'demean':
ydata = ydata - ydata.mean()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment