Package mvpa :: Package datasets :: Module channel

[hide private]
[frames] | no frames]

# Source Code for Module mvpa.datasets.channel

      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  """Dataset handling data structured in channels."""
     10
     11  __docformat__ = 'restructuredtext'
     12
     13
     14  import numpy as N
     15
     16  from mvpa.datasets.mapped import MappedDataset
     17  from mvpa.mappers.mask import MaskMapper
     18  from mvpa.base.dochelpers import enhancedDocString
     19
     20  import mvpa.support.copy as copy
     21
     22  from mvpa.base import externals
     23
     24  if externals.exists('scipy'):
     25      from scipy import signal
     26
     27
     28 -class ChannelDataset(MappedDataset):
     29      """Dataset handling data structured into channels.
     30
     31      Channels are assumes to contain several timepoints, thus this Dataset
     32      stores some additional properties (reference time `t0`, temporal
     33      distance of two timepoints `dt` and `channelids` (names)).
     34      """
     35 -    def __init__(self, samples=None, dsattr=None,
     36                   t0=None, dt=None, channelids=None, **kwargs):
     37          """Initialize ChannelDataset.
     38
     39          :Parameters:
     40            samples: ndarray
     41              Three-dimensional array: (samples x channels x timepoints).
     42            t0: float
     43              Reference time of the first timepoint. Can be used to preserve
     44              information about the onset of some stimulation. Preferably in
     45              seconds.
     46            dt: float
     47              Temporal distance between two timepoints. Has to be given in
     48              seconds. Otherwise `samplingrate` property will not return
     49              `Hz`.
     50            channelids: list
     51              List of channel names.
     52          """
     53          # if dsattr is none, set it to an empty dict
     54          if dsattr is None:
     55              dsattr = {}
     56
     57          # check samples
     58          if not samples is None and len(samples.shape) != 3:
     59                  raise ValueError, \
     60                    "ChannelDataset takes 3D array as samples."
     61
     62          # charge dataset properties
     63          # but only if some value
     64          if (not dt is None) or not dsattr.has_key('ch_dt'):
     65              dsattr['ch_dt'] = dt
     66          if (not channelids is None) or not dsattr.has_key('ch_ids'):
     67              dsattr['ch_ids'] = channelids
     68          if (not t0 is None) or not dsattr.has_key('ch_t0'):
     69              dsattr['ch_t0'] = t0
     70
     71          # come up with mapper if fresh samples were provided
     72          if not samples is None:
     73              mapper = MaskMapper(N.ones(samples.shape[1:], dtype='bool'))
     74          else:
     75              # Doesn't make difference at the moment, but might come 'handy'?
     76              mapper = dsattr.get('mapper', None)
     77
     78          # init dataset
     79          MappedDataset.__init__(self,
     80                                 samples=samples,
     81                                 mapper=mapper,
     82                                 dsattr=dsattr,
     83                                 **(kwargs))
     84
     85
     86      __doc__ = enhancedDocString('ChannelDataset', locals(), MappedDataset)
     87
     88
     89 -    def substractBaseline(self, t=None):
     90          """Substract mean baseline signal from the each timepoint.
     91
     92          The baseline is determined by computing the mean over all timepoints
     93          specified by `t`.
     94
     95          The samples of the dataset are modified in-place and nothing is
     96          returned.
     97
     98          :Parameter:
     99            t: int | float | None
    100              If an integer, `t` denotes the number of timepoints in the from the
    101              start of each sample to be used to compute the baseline signal.
    102              If a floating point value, `t` is the duration of the baseline
    103              window from the start of each sample in whatever unit
    104              corresponding to the datasets `samplingrate`. Finally, if `None`
    105              the `t0` property of the dataset is used to determine `t` as it
    106              would have been specified as duration.
    107          """
    108          # if no baseline length is given, use t0
    109          if t is None:
    110              t = N.abs(self.t0)
    111
    112          # determine length of baseline in samples
    113          if isinstance(t, float):
    114              t = N.round(t * self.samplingrate)
    115
    116          # get original data
    117          data = self.O
    118
    119          # compute baseline
    120          # XXX: shouldn't this be done per chunk?
    121          baseline = N.mean(data[:, :, :t], axis=2)
    122          # remove baseline
    123          data -= baseline[..., N.newaxis]
    124
    125          # put data back into dataset
    126          self.samples[:] = self.mapForward(data)
    127
    128
    129      if externals.exists('scipy'):
    130 -        def resample(self, nt=None, sr=None, dt=None, window='ham',
    131                       inplace=True, **kwargs):
    132              """Convenience method to resample data sample channel-wise.
    133
    134              Resampling target can be specified by number of timepoint
    135              or temporal distance or sampling rate.
    136
    137              Please note that this method only operates on
    138              `ChannelDataset` and always returns such.
    139
    140              :Parameters:
    141                nt: int
    142                  Number of timepoints to resample to.
    143                dt: float
    144                  Temporal distance of samples after resampling.
    145                sr: float
    146                  Target sampling rate.
    147                inplace : bool
    148                  If inplace=False, it would create and return a new dataset
    149                  with new samples
    150                **kwargs:
    151                  All additional arguments are passed to resample() from
    152                  scipy.signal
    153
    154              :Return:
    155                ChannelDataset
    156              """
    157              if nt is None and sr is None and dt is None:
    158                  raise ValueError, \
    159                        "Required argument missing. Either needs ntimepoints, sr or dt."
    160
    161              # get data in original shape
    162              orig_data = self.O
    163
    164              if len(orig_data.shape) != 3:
    165                  raise ValueError, "resample() only works with data from ChannelDataset."
    166
    167              orig_nt = orig_data.shape[2]
    168              orig_length = self.dt * orig_nt
    169
    170              if nt is None:
    171                  # translate dt or sr into nt
    172                  if not dt is None:
    173                      nt = orig_nt * float(self.dt) / dt
    174                  elif not sr is None:
    175                      nt = orig_nt * float(sr) / self.samplingrate
    176                  else:
    177                      raise RuntimeError, 'This should not happen!'
    178              else:
    179                  raise RuntimeError, 'This should not happen!'
    180
    181
    182              nt = N.round(nt)
    183
    184              # downsample data
    185              data = signal.resample(orig_data, nt, axis=2, window=window, **kwargs)
    186              new_dt = float(orig_length) / nt
    187
    188              dsattr = self._dsattr
    189
    190              # would be needed for not inplace generation
    191              if inplace:
    192                  dsattr['ch_dt'] = new_dt
    193                  # XXX We could have resampled range(nsamples) and
    194                  #     rounded  it. and adjust then mapper's mask
    195                  #     accordingly instead of creating a new one.
    196                  #     It would give us opportunity to assess what
    197                  #     resampling did...
    198                  mapper = MaskMapper(N.ones(data.shape[1:], dtype='bool'))
    199                  # reassign a new mapper.
    200                  dsattr['mapper'] = mapper
    201                  self.samples = mapper.forward(data)
    202                  return self
    203              else:
    204                  # we have to pass dsattr inside to don't loose
    205                  # some additional attributes such as
    206                  # labels_map
    207                  dsattr = copy.deepcopy(dsattr)
    208                  return ChannelDataset(data=self._data,
    209                                        dsattr=dsattr,
    210                                        samples=data,
    211                                        t0=self.t0,
    212                                        dt=new_dt,
    213                                        channelids=self.channelids,
    214                                        copy_data=True,
    215                                        copy_dsattr=False)
    216
    217      channelids = property(fget=lambda self: self._dsattr['ch_ids'],
    218                            doc='List of channel IDs')
    219      t0 = property(fget=lambda self: self._dsattr['ch_t0'],
    220                            doc='Temporal position of first sample in the ' \
    221                                'timeseries (in seconds) -- possibly relative ' \
    222                                'to stimulus onset.')
    223      dt = property(fget=lambda self: self._dsattr['ch_dt'],
    224                            doc='Time difference between two samples ' \
    225                                '(in seconds).')
    226      samplingrate = property(fget=lambda self: 1.0 / self._dsattr['ch_dt'],
    227                            doc='Yeah, sampling rate.')
    228