Example #1
0
def cut_segments(d, marker_tuples, offsets=[0, 0]):
  '''
  Cut a dataset into segment using (start_marker, end_marker) tuples.
  Returns a list with DataSets.
  '''
  start_off, end_off = offsets
  segments = []
  e, ei = markers_to_events(d.ys.flat)
  for (sm, em) in marker_tuples:
    segments.extend(find_segments(e, ei, sm, em))
  segments.sort()
  return [d[s + start_off:e + end_off] for (s, e) in segments]
Example #2
0
def slice(d, markers_to_class, offsets):
  '''
  Slice function, used to extract fixed-length segments of EEG from a recording.
  Returns [segment x frames x channel]
  '''
  assert len(d.feat_shape) == 1
  assert d.nclasses == 1
  start_off, end_off = offsets
  xs, ys, ids = [], [], []

  feat_shape = (end_off - start_off,) + d.feat_shape

  cl_lab = sorted(set(markers_to_class.values()))
  events, events_i = markers_to_events(d.ys.flat)
  for (mark, cl) in markers_to_class.items():
    cl_i = cl_lab.index(cl)
    for i in events_i[events==mark]: # fails if there is *ONE* event
      (start, end) = i + start_off, i + end_off
      if start < 0 or end > d.ninstances:
        logging.getLogger('psychic.utils.slice').warning(
          'Cannot extract slice [%d, %d] for class %s' % (start, end, cl))
        continue
      dslice = d[start:end]
      xs.append(dslice.xs)
      ys.append(cl_i)
      ids.append(d.ids[i, :])

  m = len(xs)
  xs = np.asarray(xs).reshape(m, np.prod(feat_shape))
  ys = np.asarray(ys)
  ys = helpers.to_one_of_n(ys.T, class_rows=range(len(cl_lab))).T
  ids = np.asarray(ids).reshape(m, d.ids.shape[1])

  event_time = np.arange(start_off, end_off) / float(get_samplerate(d))
  time_lab = ['%.3f' % ti for ti in event_time]
  feat_nd_lab = [time_lab, d.feat_lab if d.feat_lab 
    else ['f%d' % i for i in range(d.nfeatures)]]
  feat_dim_lab = ['time', 'channels']
  d = DataSet(xs=xs, ys=ys, ids=ids, cl_lab=cl_lab, 
    feat_shape=feat_shape, feat_nd_lab=feat_nd_lab, 
    feat_dim_lab=feat_dim_lab, default=d)
  return d.sorted()
Example #3
0
def cut_segments(d, marker_tuples, offsets=[0, 0]):
    """
  Cut a dataset into segments using (start_marker, end_marker) tuples.

  Parameters
  ----------
  d : :class:`psychic.DataSet`
    Continuous data to cut into segments.
  marker_tuples : list of tuples
    A list of (start_marker, end_marker) marker codes delimiting each
    type of segment.

  Returns
  -------
  data : list of :class:`psychic.DataSet`
    A list with datasets.
  """
    start_off, end_off = offsets
    segments = []
    e, ei, _ = markers_to_events(d.labels.flat)
    for (sm, em) in marker_tuples:
        segments.extend(find_segments(e, ei, sm, em))
    segments.sort()
    return [d[s + start_off : e + end_off] for (s, e) in segments]
Example #4
0
def plot_eeg(
         data,
         samplerate=None,
         vspace=None,
         draw_markers=True, 
         mirror_y=False,
         fig=None,
         mcolors=['b', 'r', 'g', 'c', 'm', 'y', 'k', '#ffaa00'],
         mlinestyles=['-','-','-','-','-','-','-','-'],
         mlinewidths=[1,1,1,1,1,1,1,1],
         start=0):
    '''
    Plot EEG data contained in a golem dataset.

    Parameters
    ----------
    data : :class:`psychic.DataSet`
        The data to plot. Assumed to be continuous data (channels x time)
    samplerate : float (optional)
        The sample rate of the data. When omitted,
        :func:`psychic.get_samplerate` is used to estimate it.
    vspace : float (optional)
        The amount of vertical spacing between channels. When omitted, the
        minimum value is taken so that no channels overlap.
    draw_markers : bool (default=True)
        When set, event markers are drawn as vertical lines in the plot.
    mirror_y : bool (default=False)
        When set, negative is plotted up. Some publications use this style
        of plotting.
    fig : :class:`matplotlib.Figure` (optional)
        Normally, a new figure is created to hold the plot. However, the user
        can specify the figure in which to draw. This is useful if the user
        wants to remain in control of the size of the figure and the location
        of the axes.
    mcolors : list (optional)
        Sets a color for each marker type. The vertical lines and text labels for
        events of a given type will be drawn in the specified color. Values are given
        as matplotlib color specifications.
        See: http://matplotlib.org/api/colors_api.html
    mlinestyles : list (optional)
        Line style specifications for each marker type.
        See: http://matplotlib.org/1.3.0/api/pyplot_api.html#matplotlib.pyplot.plot
    mlinewidths : list (optional)
        Line width specifications for each marker type. Vertical lines are
        drawn at the specified widths. Values are given in points.
    start : float (default=0)
        Time which is to be taken as t=0. Normally when plotting a time range,
        the time axis will reflect absolute time. For example, when plotting
        the time range 2 to 4 seconds, the time axis will start at 2 seconds.
        Setting the ``start`` parameter to 2 will in this case make the time
        axis range from 0 to 2 seconds, and setting this parameter to 3 will
        make the time axis range from -1 to 1 seconds.

    Returns
    -------
    fig : :class:`matplotlib.Figure`
        The figure object containing the plot. When a figure is specified with
        the ``fig`` parameter, the same figure is returned.
    '''

    assert data.data.ndim == 2

    num_channels, num_samples = data.data.shape

    # Spread out the channels
    if vspace is None:
        vspace = np.max(np.max(data.data, axis=1) - np.min(data.data, axis=1))

    bases = vspace * np.arange(0, num_channels)[::-1] - np.mean(data.data, axis=1)
    to_plot = data.data + np.tile( bases, (num_samples,1) ).T

    if fig is None:
        fig = plot.figure()

    # Plot EEG
    fig.subplots_adjust(right=0.85)
    axes = plot.subplot(111)
    _draw_eeg_frame(num_channels, vspace, data.ids.T-start, data.feat_lab[0], mirror_y)
    plot.plot(data.ids.T-start, to_plot.T)

    # Draw markers
    if draw_markers:
        trans = transforms.blended_transform_factory(axes.transData, axes.transAxes)

        events, offsets, _ = markers_to_events(data.labels[0,:])
        eventi = {}
        for i,e in enumerate(np.unique(events)):
            eventi[e] = i

        for e,o in zip(events, offsets):
            i = eventi[e]
            x = data.ids[0,o] # In data coordinates
            y = 1.01        # In axes coordinates
            plot.axvline(x,
                    color=mcolors[i%len(mcolors)],
                    linestyle=mlinestyles[i%len(mlinestyles)],
                    linewidth=mlinewidths[i%len(mlinewidths)])
            plot.text(x, y, str(e), transform=trans, ha='center', va='bottom')

    plot.ylabel('Channels')
    plot.xlabel('Time (s)')
    plot.grid()

    return fig
Example #5
0
def slice(d, markers_to_class, offsets):
    '''
    Slice function, used to extract fixed-length segments (called trials) of
    EEG from a recording. Opposite of :func:`psychic.concatenate_trials`.
    Segments are sliced based on the onset of some event code.

    Given for example an EEG recording which contains two marker codes:

    1. Left finger tapping
    2. Right finger tapping

    Trials can be extracted in the following manner:

    >>> import psychic
    >>> d = psychic.load_bdf(psychic.find_data_path('priming-short.bdf'))
    >>> mdict = {1:'related', 2:'unrelated'}
    >>> sample_rate = psychic.get_samplerate(d)
    >>> begin = int(-0.2 * sample_rate)
    >>> end = int(1.0 * sample_rate)
    >>> trials = psychic.slice(d, mdict, (begin, end))
    >>> print trials
    DataSet with 208 instances, 12280 features [40x307], 2 classes: [104, 104], extras: []
     
    Parameters
    ----------
    markers_to_class : dict
        A dictionary containing as keys the event codes to use as onset of the
        trial and as values a class label for the resulting trials. For example
        ``{1:'left finger tapping', 2:'right finger tapping'}``
    offsets : tuple
        Indicates the time (start, end), relative to the onset of marker, to
        extract as trial. Values are given in samples.

    Returns
    -------
    d : :class:`DataSet`
        The extracted segments:

        - ``d.data``: [channels x samples x trials]
        - ``d.labels``: [classes x trials]
        - ``d.ids``: Timestamps indicating the marker onsets
        - ``d.cl_lab``: The class labels as specified in the
          ``markers_to_class`` dictionary
        - ``d.feat_lab``: Feature labels for the axes [channels (strings),
          time in seconds (floats)]
    '''
    assert len(d.feat_shape) == 1, 'Data must be continuous EEG.'
    assert d.labels.shape[0] == 1 and d.labels.dtype == np.int, ('Labels are'
        'the wrong format. It must be an integer marker stream.')
    start_off, end_off = offsets
    data, labels, ids = [], [], []
    
    cl_lab = sorted(set(markers_to_class.values()))
    events, events_i, events_d = markers.markers_to_events(d.labels.flat)
    for (mark, cl) in markers_to_class.items():
        cl_i = cl_lab.index(cl)
        for i in events_i[events==mark]: # fails if there is *ONE* event
            (start, end) = i + start_off, i + end_off
            if start < 0 or end > d.ninstances:
                logging.getLogger('psychic.utils.slice').warning(
                    'Cannot extract slice [%d, %d] for class %s'
                    % (start, end, cl))
                continue
            dslice = d[start:end]
            data.append(dslice.data)
            labels.append(cl_i)
            ids.append(d.ids[:,i])
    
    event_time = np.arange(start_off, end_off) / float(utils.get_samplerate(d))
    feat_lab = [d.feat_lab[0], event_time.tolist()]

    if len(data) == 0:
        data = np.zeros(d.feat_shape + (len(event_time),0))
        labels = np.zeros((len(cl_lab),0))
        ids = np.zeros((1,0))
    else:
        data = np.concatenate([x[...,np.newaxis] for x in data], axis=2)
        labels = helpers.to_one_of_n(labels, class_rows=range(len(cl_lab)))
        ids = np.atleast_2d(np.vstack(ids).T)

    feat_dim_lab = ['channels', 'time']

    d = DataSet(
        data=data,
        labels=labels,
        ids=ids,
        cl_lab=cl_lab, 
        feat_lab=feat_lab, 
        feat_dim_lab=feat_dim_lab,
        default=d
    )
    return d.sorted()