Package mvpa :: Package misc :: Package fsl :: Module base

[hide private]
[frames] | no frames]

# Source Code for Module mvpa.misc.fsl.base

      1  # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
      2  # vi: set ft=python sts=4 ts=4 sw=4 et:
      3  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
      4  #
      5  #   See COPYING file distributed along with the PyMVPA package for the
      6  #   copyright and license terms.
      7  #
      8  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
      9  """Tiny snippets to interface with FSL easily."""
     10
     11  __docformat__ = 'restructuredtext'
     12
     13  import numpy as N
     14
     15  from mvpa.misc.io import ColumnData
     16  from mvpa.misc.support import Event
     17
     18  if __debug__:
     19      from mvpa.base import debug
     20
     21
     22 -class FslEV3(ColumnData):
     23      """IO helper to read FSL's EV3 files.
     24
     25      This is a three-column textfile format that is used to specify stimulation
     26      protocols for fMRI data analysis in FSL's FEAT module.
     27
     28      Data is always read as `float`.
     29      """
     30 -    def __init__(self, source):
     31          """Read and write FSL EV3 files.
     32
     33          :Parameter:
     34            source: filename of an EV3 file
     35          """
     36          # init data from known format
     37          ColumnData.__init__(self, source,
     38                              header=['onsets', 'durations', 'intensities'],
     39                              sep=None, dtype=float)
     40
     41
     42 -    def getNEVs(self):
     43          """Returns the number of EVs in the file.
     44          """
     45          return self.nrows
     46
     47
     48 -    def getEV(self, evid):
     49          """Returns a tuple of (onset time, simulus duration, intensity) for a
     50          certain EV.
     51          """
     52          return (self['onsets'][evid],
     53                  self['durations'][evid],
     54                  self['intensities'][evid])
     55
     56
     57 -    def tofile(self, filename):
     58          """Write data to a FSL EV3 file.
     59          """
     60          ColumnData.tofile(self, filename,
     61                            header=False,
     62                            header_order=['onsets', 'durations', 'intensities'],
     63                            sep=' ')
     64
     65
     66 -    def toEvents(self, **kwargs):
     67          """Convert into a list of `Event` instances.
     68
     69          :Parameters:
     70            kwargs
     71              Any keyword arugment provided would be replicated, through all
     72              the entries. Useful to specify label or even a chunk
     73          """
     74          return \
     75              [Event(onset=self['onsets'][i],
     76                     duration=self['durations'][i],
     77                     features=[self['intensities'][i]],
     78                     **kwargs)
     79               for i in xrange(self.nevs)]
     80
     81
     82      onsets = property(fget=lambda self: self['onsets'])
     83      durations = property(fget=lambda self: self['durations'])
     84      intensities = property(fget=lambda self: self['intensities'])
     85      nevs = property(fget=getNEVs)
     86
     87
     88
     89 -class McFlirtParams(ColumnData):
     90      """Read and write McFlirt's motion estimation parameters from and to text
     91      files.
     92      """
     93      header_def = ['rot1', 'rot2', 'rot3', 'x', 'y', 'z']
     94
     95 -    def __init__(self, source):
     96          """Initialize McFlirtParams
     97
     98          :Parameter:
     99              source: str
    100                  Filename of a parameter file.
    101          """
    102          ColumnData.__init__(self, source,
    103                              header=McFlirtParams.header_def,
    104                              sep=None, dtype=float)
    105
    106
    107 -    def tofile(self, filename):
    108          """Write motion parameters to file.
    109          """
    110          ColumnData.tofile(self, filename,
    111                            header=False,
    112                            header_order=McFlirtParams.header_def,
    113                            sep=' ')
    114
    115
    116 -    def plot(self):
    117          """Produce a simple plot of the estimated translation and rotation
    118          parameters using.
    119
    120          You still need to can pylab.show() or pylab.savefig() if you want to
    121          see/get anything.
    122          """
    123          # import internally as it takes some time and might not be needed most
    124          # of the time
    125          import pylab as P
    126
    127          # translations subplot
    128          P.subplot(211)
    129          P.plot(self.x)
    130          P.plot(self.y)
    131          P.plot(self.z)
    132          P.ylabel('Translations in mm')
    133          P.legend(('x', 'y', 'z'), loc=0)
    134
    135          # rotations subplot
    136          P.subplot(212)
    137          P.plot(self.rot1)
    138          P.plot(self.rot2)
    139          P.plot(self.rot3)
    140          P.ylabel('Rotations in rad')
    141          P.legend(('rot1', 'rot2', 'rot3'), loc=0)
    142
    143
    144 -    def toarray(self):
    145          """Returns the data as an array with six columns (same order as in file).
    146          """
    147          import numpy as N
    148
    149          # return as array with time axis first
    150          return N.array([self[i] for i in McFlirtParams.header_def],
    151                         dtype='float').T
    152
    153
    154 -class FslGLMDesign(object):
    155      """Load FSL GLM design matrices from file.
    156
    157      Be aware that such a desig matrix has its regressors in columns and the
    158      samples in its rows.
    159      """
    160 -    def __init__(self, source):
    161          """
    162          :Parameter:
    163            source: filename
    164              Compressed files will be read as well, if their filename ends with
    165              '.gz'.
    166          """
    167          # XXX maybe load from array as well
    168          self._loadFile(source)
    169
    170
    171 -    def _loadFile(self, fname):
    172          """Helper function to load GLM definition from a file.
    173          """
    174          # header info
    175          nwaves = 0
    176          ntimepoints = 0
    177          matrix_offset = 0
    178
    179          # open the file compressed or not
    180          if fname.endswith('.gz'):
    181              import gzip
    182              fh = gzip.open(fname, 'r')
    183          else:
    184              fh = open(fname, 'r')
    185
    186          # read header
    187          for i, line in enumerate(fh):
    188              if line.startswith('/NumWaves'):
    189                  nwaves = int(line.split()[1])
    190              if line.startswith('/NumPoints'):
    191                  ntimepoints = int(line.split()[1])
    192              if line.startswith('/PPheights'):
    193                  self.ppheights = [float(i) for i in line.split()[1:]]
    194              if line.startswith('/Matrix'):
    195                  matrix_offset = i + 1
    196
    197          # done with the header, now revert to NumPy's loadtxt for convenience
    198          fh.close()
    199          self.mat = N.loadtxt(fname, skiprows=matrix_offset)
    200
    201          # checks
    202          if not self.mat.shape == (ntimepoints, nwaves):
    203              raise IOError, "Design matrix file '%s' did not contain expected " \
    204                             "matrix size (expected %s, got %s)" \
    205                             % (fname, str((ntimepoints, nwaves)), self.mat.shape)
    206
    207
    208 -    def plot(self, style='lines', **kwargs):
    209          """Visualize the design matrix.
    210
    211          :Parameters:
    212            style: 'lines', 'matrix'
    213            **kwargs:
    214              Additional arguments will be passed to the corresponding matplotlib
    215              plotting functions 'plot()' and 'pcolor()' for 'lines' and 'matrix'
    216              plots respectively.
    217          """
    218          # import internally as it takes some time and might not be needed most
    219          # of the time
    220          import pylab as P
    221
    222          if style == 'lines':
    223              # common y-axis
    224              yax = N.arange(0, self.mat.shape[0])
    225              axcenters = []
    226              col_offset = max(self.ppheights)
    227
    228              # for all columns
    229              for i in xrange(self.mat.shape[1]):
    230                  axcenter = i * col_offset
    231                  P.plot(self.mat[:, i] + axcenter, yax, **kwargs)
    232                  axcenters.append(axcenter)
    233
    234              P.xticks(N.array(axcenters), range(self.mat.shape[1]))
    235          elif style == 'matrix':
    236              P.pcolor(self.mat, **kwargs)
    237              ticks = N.arange(1, self.mat.shape[1]+1)
    238              P.xticks(ticks - 0.5, ticks)
    239          else:
    240              raise ValueError, "Unknown plotting style '%s'" % style
    241
    242          # labels and turn y-axis upside down
    243          P.ylabel('Samples (top to bottom)')
    244          P.xlabel('Regressors')
    245          P.ylim(self.mat.shape[0],0)
    246
    247
    248 -def read_fsl_design(fsf_file):
    249      """Reads an FSL FEAT design.fsf file and return the content as a dictionary.
    250
    251      :Parameters:
    252        fsf_file : filename, file-like
    253      """
    254      # This function was originally contributed by Russell Poldrack
    255
    256      if isinstance(fsf_file, basestring):
    257          infile = open(fsf_file, 'r')
    258      else:
    259          infile = fsf_file
    260
    261      # target dict
    262      fsl = {}
    263
    264      # loop over all lines
    265      for line in infile:
    266          line = line.strip()
    267          # if there is nothing on the line, do nothing
    268          if not line or line[0] == '#':
    269              continue
    270
    271          # strip leading TCL 'set'
    272          key, value = line.split(None, 2)[1:]
    273
    274          # fixup the 'y-' thing
    275          if value == 'y-':
    276              value = "y"
    277
    278          # special case of variable keyword
    279          if line.count('_files('):
    280              # e.g. feat_files(1) -> feat_files
    281              key = key.split('(')[0]
    282
    283          # decide which type we have for the value
    284          # int?
    285          if value.isdigit():
    286              fsl[key] = int(value)
    287          else:
    288              # float?
    289              try:
    290                  fsl[key] = float(value)
    291              except ValueError:
    292                  # must be string then, but...
    293                  # sometimes there are quotes, sometimes not, but if the value
    294                  # should be a string we remove them, since the value is already
    295                  # of this type
    296                  fsl[key] = value.strip('"')
    297
    298      return fsl
    299