def events(vhdr_path=None): if vhdr_path is None: vhdr_path = ui.ask_file("Pick a Brain Vision EEG Header File", "Pick a Brain Vision EEG Header File", ext=[('vhdr', 'Brain Vision Header File')]) if not vhdr_path: return hdr = vhdr(vhdr_path) if hdr.markerfile is None: raise IOError("No marker file referenced in %r" % vhdr_path) elif hdr.DataType == 'FREQUENCYDOMAIN': raise NotImplementedError txt = open(hdr.markerfile).read() m = marker_re.findall(txt) m = np.array(m) name, _ = os.path.split(os.path.basename(hdr.path)) ds = dataset(name=name) ds['Mk'] = var(np.array(m[:,0], dtype=int)) ds['event_type'] = factor(m[:,1]) ds['event_ID'] = var(np.array(m[:,3], dtype=int)) ds['i_start'] = var(np.array(m[:,4], dtype=int)) ds['points'] = var(np.array(m[:,5], dtype=int)) ds['channel'] = var(np.array(m[:,6], dtype=int)) ds.info['hdr'] = hdr ds.info['samplingrate'] = hdr.samplingrate return ds
def export_durs(self): ds = dataset() idx = self.words == 'sp' words = self.words[~idx] durs = self.word_durs[~idx] ds['words'] = factor([first.lower() + second.lower() for first, second in zip(words[::2], words[1::2])]) ds['c1_dur'] = var(durs[::2]) ds['c2_dur'] = var(durs[1::2]) return ds
def _resample(Y, unit=None, replacement=True, samples=1000): """ Generator function to resample a dependent variable (Y) multiple times unit: factor specdifying unit of measurement (e.g. subject). If unit is specified, resampling proceeds by first resampling the categories of unit (with or without replacement) and then shuffling the values within unites (no replacement). replacement: whether random samples should be drawn with replacement or without samples: number of samples to yield """ if isvar(Y): Yout = Y.copy('_resampled') Y else: Y = var(Y) Yout = var(Y.copy(), name="Y resampled") if unit: ct = celltable(Y, unit) unit_data = ct.get_data(out=list) unit_indexes = ct.data_indexes.values() x_out = Yout.x if replacement: n = len(ct.indexes) for sample in xrange(samples): source_ids = np.random.randint(n, size=n) for index, source_index in zip(unit_indexes, source_ids): data = unit_data[source_index] np.random.shuffle(data) x_out[index] = data yield Yout else: for sample in xrange(samples): random.shuffle(unit_data) for index, data in zip(unit_indexes, unit_data): np.random.shuffle(data) x_out[index] = data yield Yout else: if replacement: N = Y.N for i in xrange(samples): index = np.random.randint(N) Yout.x = Y.x[index] yield Yout else: for i in xrange(samples): np.random.shuffle(Yout.x) yield Yout
def export_durs(self): ds = dataset() idx = self.words == 'sp' words = self.words[~idx] durs = self.word_durs[~idx] ds['words'] = factor([ first.lower() + second.lower() for first, second in zip(words[::2], words[1::2]) ]) ds['c1_dur'] = var(durs[::2]) ds['c2_dur'] = var(durs[1::2]) return ds
def add_T_to(self, ds, Id='eventID', t_edf='t_edf'): """ Add edf trigger times as a variable to dataset ds. These can then be used for Edf.add_by_T(ds) after ds hads been decimated. Parameters ---------- ds : dataset The dataset to which the variable is added Id : str | var | None variable (or its name in the dataset) containing event IDs. Values in this variable are checked against the events in the EDF file, and an error is raised if there is a mismatch. This test can be skipped by setting Id=None. t_edf : str Name for the target variable holding the edf trigger times. """ if Id: self.assert_Id_match(ds=ds, Id=Id) if isinstance(Id, str): Id = ds[Id] ds[t_edf] = var(self.triggers['T'])
def fiff_mne(ds, fwd='{fif}*fwd.fif', cov='{fif}*cov.fif', label=None, name=None, tstart= -0.1, tstop=0.6, baseline=(None, 0)): """ adds data from one label as """ if name is None: if label: _, lbl = os.path.split(label) lbl, _ = os.path.splitext(lbl) name = lbl.replace('-', '_') else: name = 'stc' info = ds.info['info'] raw = ds.info['raw'] fif_name = raw.info['filename'] fif_name, _ = os.path.splitext(fif_name) if fif_name.endswith('raw'): fif_name = fif_name[:-3] fwd = fwd.format(fif=fif_name) if '*' in fwd: d, n = os.path.split(fwd) names = fnmatch.filter(os.listdir(d), n) if len(names) == 1: fwd = os.path.join(d, names[0]) else: raise IOError("No unique fwd file matching %r" % fwd) cov = cov.format(fif=fif_name) if '*' in cov: d, n = os.path.split(cov) names = fnmatch.filter(os.listdir(d), n) if len(names) == 1: cov = os.path.join(d, names[0]) else: raise IOError("No unique cov file matching %r" % cov) fwd = mne.read_forward_solution(fwd, force_fixed=False, surf_ori=True) cov = mne.Covariance(cov) inv = _mn.make_inverse_operator(info, fwd, cov, loose=0.2, depth=0.8) epochs = mne_Epochs(ds, tstart=tstart, tstop=tstop, baseline=baseline) # mne example: snr = 3.0 lambda2 = 1.0 / snr ** 2 if label is not None: label = mne.read_label(label) stcs = _mn.apply_inverse_epochs(epochs, inv, lambda2, dSPM=False, label=label) x = np.vstack(s.data.mean(0) for s in stcs) s = stcs[0] dims = ('case', var(s.times, 'time'),) ds[name] = ndvar(x, dims, properties=None, info='') return stcs
def _get_vessel_for_Y(self, Ydata): Ydata = np.array([self._cfunc(data, axis=0) for data in Ydata]) T = np.arange(self._tw.tstart, self._tw.tend, 1 / self._samplingrate) time = _vsl.var(T, name='time') dims = ('case', time) properties = {'samplingrate': self._samplingrate} Y = _vsl.ndvar(Ydata, dims, properties=properties, name=self._name) return Y
def get_triggers(self, Id='Id', T='t_edf'): """ Returns a dataset with trigger Ids and corresponding Edf time values """ ds = dataset() ds[Id] = var(self.triggers['Id']) ds[T] = self.get_T(name=T) return ds
def evoked_ndvar(evoked, name='MEG'): "Convert an mne Evoked object of a list thereof to an ndvar" if isinstance(evoked, mne.fiff.Evoked): x = evoked.data dims = () else: x = np.array([e.data for e in evoked]) dims = ('case',) evoked = evoked[0] sensor = sensor_net(evoked) time = var(evoked.times, name='time') properties = {'colorspace': _cs.get_MEG(2e-13)} return ndvar(x, dims + (sensor, time), properties=properties, name=name)
def mark(self, ds, tstart= -0.1, tstop=0.6, good=None, bad=False, use=['ESACC', 'EBLINK'], T='t_edf', target='accept'): """ Mark events in ds as acceptable or not. ds needs to contain edf trigger times in a variable whose name is specified by the ``T`` argument. Parameters ---------- ds : dataset dataset that contains the data to work with. tstart : scalar start of the time window relevant for rejection. tstop : scalar stop of the time window relevant for rejection. good : bool | None vale assigned to epochs that should be retained based on the eye-tracker data. bad : bool | None value that is assigned to epochs that should be rejected based on the eye-tracker data. use : list of str Artifact categories to include T : var variable providing the trigger time values target : var variable to which the good/bad values are assigned (if it does not exist, a new variable will be created with all values True initially) """ if isinstance(target, str): if target in ds: target = ds[target] else: ds[target] = target = var(np.ones(ds.n_cases, dtype=bool)) if isinstance(T, str): T = ds[T] accept = self.get_accept(T, tstart=tstart, tstop=tstop, use=use) if good is not None: target[accept] = good if bad is not None: target[np.invert(accept)] = bad
def stc_ndvar(stc, subject='fsaverage', name=None, check=True): """ create an ndvar object from an mne SourceEstimate object stc : SourceEstimate | list of SourceEstimates The source estimate object(s). subject : str MRI subject (used for loading MRI in PySurfer plotting) name : str | None Ndvar name. check : bool If multiple stcs are provided, check if all stcs have the same times and vertices. """ if isinstance(stc, mne.SourceEstimate): case = False x = stc.data else: case = True stcs = stc stc = stcs[0] if check: vert_lh, vert_rh = stc.vertno times = stc.times for stc_ in stcs[1:]: assert np.all(times == stc_.times) lh, rh = stc_.vertno assert np.all(vert_lh == lh) assert np.all(vert_rh == rh) x = np.array([s.data for s in stcs]) time = var(stc.times, name='time') ss = source_space(stc.vertno, subject=subject) if case: dims = ('case', ss, time) else: dims = (ss, time) return ndvar(x, dims, name=name)
def get_dataset(self): "get a dataframe containing Y and covariates" Y, covs = self._collect_data() indexes = Y.keys() Ydata = [Y[index] for index in indexes] Y = self._get_vessel_for_Y(Ydata) ds = _vsl.dataset(Y) # create _data objects for var, valdict in covs.iteritems(): X = [valdict[index] for index in indexes] if var.dict_enabled: Y = _vsl.factor(X, name=var.name, random=var.random, labels=var.dictionary, colors=var._color_dict) else: Y = _vsl.var(X, name=var.name) ds.add(Y) return ds
def var(path=None, name=None): """ Loads a ``var`` object from a text file by splitting at white-spaces. path : str(path) | None Source file. If None, a system file dialog is opened. name : str | None Name for the var. """ if path is None: path = ui.ask_file("Select var File", "()") FILE = open(path) lines = FILE.read().split() FILE.close() is_bool = all(line in ['True', 'False'] for line in lines) if is_bool: x = np.genfromtxt(path, dtype=bool) else: x = np.loadtxt(path) return _data.var(x, name=None)
def __init__(self, dataset, data='MEG', target='accept', nplots=(6, 6), plotsize=(3, 1.5), mean=True, topo=True, ylim=None, fill=True, aa=False, dpi=50): """ Plots all cases in the collection segment and allows visual selection of cases. The selection can be retrieved through the get_selection Method. Arguments ---------- dataset : dataset dataset on which to perform the selection. nplots : 1 | 2 | (i, j) Number of plots (including topo plots and mean). mean : bool Plot the page mean on each page. topo : bool Show a dynamically updated topographic plot at the bottom right. ylim : scalar y-limit of the butterfly plots. fill : bool Only show extrema in the butterfly plots, instead of all traces. This is faster for data with many channels. aa : bool Antialiasing (matplolibt parameter). Example:: >>> select_cases_butterfly(my_dataset) [... visual selection of cases ...] >>> cases = my_dataset['reject'] == False >>> pruned_dataset = my_dataset[cases] """ # interpret plotting args # variable keeping track of selection if isinstance(data, basestring): data = dataset[data] self._data = data if np.prod(nplots) == 1: nplots = (1, 1) mean = False topo = False elif np.prod(nplots) == 2: mean = False if nplots == 2: nplots = (1, 2) if isinstance(target, basestring): try: target = dataset[target] except KeyError: x = np.ones(dataset.N, dtype=bool) target = _data.var(x, name=target) dataset.add(target) self._target = target self._plot_mean = mean self._plot_topo = topo # prepare segments self._nplots = nplots n_per_page = self._n_per_page = np.prod(nplots) - bool(topo) - bool(mean) n_pages = dataset.N // n_per_page + bool(dataset.N % n_per_page) self._n_pages = n_pages # get a list of IDS for each page self._segs_by_page = [] for i in xrange(n_pages): start = i * n_per_page stop = min((i + 1) * n_per_page, dataset.N) self._segs_by_page.append(range(start, stop)) # init wx frame title = "select_cases_butterfly -> %r" % target.name figsize = (plotsize[0] * nplots[0], plotsize[1] * nplots[1]) super(self.__class__, self).__init__(title=title, figsize=figsize, dpi=dpi) # setup figure self.figure.subplots_adjust(left=.01, right=.99, bottom=.05, top=.95, hspace=.5) # connect canvas self.canvas.mpl_connect('button_press_event', self._on_click) if self._is_wx: self.canvas.mpl_connect('axes_leave_event', self._on_leave_axes) # compile plot kwargs: self._bfly_kwargs = {'extrema': fill} if ylim is None: ylim = data.properties.get('ylim', None) if ylim: self._bfly_kwargs['ylim'] = ylim # finalize self._dataset = dataset self.show_page(0) self._frame.store_canvas() self._show()
def get_T(self, name='t_edf'): "returns all trigger times in the dataset" return var(self.triggers['T'], name=name)
def _get_vessel_for_Y(self, Ydata): Ydata = [self._cfunc(data) for data in Ydata] Y = _vsl.var(Ydata, name=self._name) return Y
def epochs_ndvar(epochs, name='MEG', meg=True, eeg=False, exclude='bads', mult=1, unit='T', properties=None, sensors=None): """ Convert an mne.Epochs object to an ndvar. Parameters ---------- epoch : mne.Epochs The epochs object name : None | str Name for the ndvar. meg : bool or string MEG channels to include (:func:`mne.fiff.pick_types` kwarg). If True include all MEG channels. If False include None If string it can be 'mag' or 'grad' to select only gradiometers or magnetometers. It can also be 'ref_meg' to get CTF reference channels. eeg : bool If True include EEG channels (:func:`mne.fiff.pick_types` kwarg). exclude : list of string | str Channels to exclude (:func:`mne.fiff.pick_types` kwarg). If 'bads' (default), exclude channels in info['bads']. If empty do not exclude any. mult : scalar multiply all data by a constant. If used, the ``unit`` kwarg should specify the target unit, not the source unit. unit : str Unit of the data (default is 'T'). target : str name for the new ndvar containing the epoch data reject : None | scalar Threshold for rejecting epochs (peak to peak). Requires a for of mne-python which implements the Epochs.model['index'] variable. raw : None | mne.fiff.Raw Raw file providing the data; if ``None``, ``ds.info['raw']`` is used. sensors : None | eelbrain.vessels.sensors.sensor_net The default (``None``) reads the sensor locations from the fiff file. If the fiff file contains incorrect sensor locations, a different sensor_net can be supplied through this kwarg. """ props = {'proj': 'z root', 'unit': unit, 'ylim': 2e-12 * mult, 'summary_ylim': 3.5e-13 * mult, 'colorspace': _cs.get_MEG(2e-12 * mult), 'summary_colorspace': _cs.get_MEG(2e-13 * mult), 'samplingrate': epochs.info['sfreq'], } if properties: props.update(properties) picks = mne.fiff.pick_types(epochs.info, meg=meg, eeg=eeg, stim=False, eog=False, include=[], exclude=exclude) x = epochs.get_data()[:, picks] if mult != 1: x *= mult if sensors is None: sensor = sensor_net(epochs, picks=picks) else: sensor = sensors time = var(epochs.times, name='time') return ndvar(x, ('case', sensor, time), properties=props, name=name)
def events(raw=None, merge= -1, proj=False, name=None, stim_channel='STI 014', stim_channel_bl=0, verbose=False): """ Read events from a raw fiff file. Use :func:`fiff_epochs` to load MEG data corresponding to those events. Parameters ---------- raw : str(path) | None | mne.fiff.Raw The raw fiff file from which to extract events (if ``None``, a file dialog will be displayed). merge : int use to merge events lying in neighboring samples. The integer value indicates over how many samples events should be merged, and the sign indicates in which direction they should be merged (negative means towards the earlier event, positive towards the later event). proj : bool | str Path to the projections file that will be loaded with the raw file. ``'{raw}'`` will be expanded to the raw file's path minus extension. With ``proj=True``, ``'{raw}_*proj.fif'`` will be used, looking for any projection file starting with the raw file's name. If multiple files match the pattern, a ValueError will be raised. name : str | None A name for the dataset. If ``None``, the raw filename will be used. stim_channel : str Name of the trigger channel. stim_channel_bl : int For corrupted event channels: After kit2fiff conversion of sqd files with unused trigger channels, the resulting fiff file's event channel can contain a baseline other than 0. This interferes with normal event extraction. If the baseline value is provided as parameter, the events can still be extracted. Returns ------- events : dataset A dataset with the following variables: - *i_start*: the index of the event in the raw file. - *eventID*: the event value. The dataset's info dictionary contains the following values: - *raw*: the mne Raw object. - *samplingrate*: the samplingrate of the raw file. """ if raw is None or isinstance(raw, basestring): raw = Raw(raw, proj=proj, verbose=verbose) if name is None: raw_file = raw.info['filename'] name = os.path.basename(raw_file) if stim_channel_bl: pick = mne.event.pick_channels(raw.info['ch_names'], include=stim_channel) data, _ = raw[pick, :] idx = np.where(np.abs(np.diff(data[0])) > 0)[0] # find baseline NULL-events values = data[0, idx + 1] valid_events = np.where(values != stim_channel_bl)[0] idx = idx[valid_events] values = values[valid_events] N = len(values) events = np.empty((N, 3), dtype=np.int32) events[:, 0] = idx events[:, 1] = np.zeros_like(idx) events[:, 2] = values else: events = mne.find_events(raw, verbose=verbose, stim_channel=stim_channel) if len(events) == 0: raise ValueError("No events found!") if merge: index = np.ones(len(events), dtype=bool) diff = np.diff(events[:, 0]) where = np.where(diff <= abs(merge))[0] if merge > 0: # drop the earlier event index[where] = False else: # drop the later event index[where + 1] = False # move the trigger value to the earlier event for w in reversed(where): i1 = w i2 = w + 1 events[i1, 2] = events[i2, 2] events = events[index] istart = var(events[:, 0], name='i_start') event = var(events[:, 2], name='eventID') info = {'raw': raw, 'samplingrate': raw.info['sfreq'], 'info': raw.info} return dataset(event, istart, name=name, info=info)
def tsv(path=None, names=True, types='auto', empty='nan', delimiter=None, skiprows=0): """ returns a ``dataset`` with data from a tab-separated values file. Parameters ---------- names : list of str | bool * ``['name1', ...]`` use these names * ``True``: look for names on the first line of the file * ``False``: use "v1", "v2", ... types : 'auto' | list of int * ``'auto'`` -> import as var if all values can be converted float, otherwise as factor * list of 0=auto, 1=factor, 2=var. e.g. ``[0,1,1,0]`` empty : value to substitute for empty cells delimiter : str value delimiting cells in the input file (None = any whitespace; e.g., ``'\\t'``) skiprows : int Skip so many rows at the beginning of the file (for tsv files with headers). Column names (if names==True) are expected to come after the skipped rows. """ if path is None: path = ui.ask_file("Select file to import as dataframe", "Select file to import as dataframe") if not path: return with open(path) as f: for i in xrange(skiprows): f.readline() # read / create names if names == True: names = f.readline().split(delimiter) names = [n.strip().strip('"') for n in names] lines = [] for line in f: values = [] for v in line.split(delimiter): v = v.strip() if not v: v = empty values.append(v) lines.append(values) n_vars = len(lines[0]) if not names: names = ['v%i' % i for i in xrange(n_vars)] n = len(names) # decide whether to drop first column if n_vars == n: start = 0 elif n_vars == n + 1: start = 1 else: raise ValueError("number of header different from number of data") if types in ['auto', None, False, True]: types = [0] * n else: assert len(types) == n # prepare for reading data data = [] for _ in xrange(n): data.append([]) # read rest of the data for line in lines: for i, v in enumerate(line[start:]): for str_del in ["'", '"']: if v[0] == str_del: v = v.strip(str_del) types[i] = 1 data[i].append(v) ds = _data.dataset(name=os.path.basename(path)) for name, values, force_type in zip(names, data, types): v = np.array(values) if force_type in [0, 2]: try: v = v.astype(float) f = _data.var(v, name=name) except: f = _data.factor(v, name=name) else: f = _data.factor(v, name=name) ds.add(f) return ds
def _ax_im_array(ax, layers, x='time', # vmax=None, xlabel=True, ylabel=True, title=None, tick_spacing=.3): """ plots segment data as im define a colorspace by supplying one of those kwargs: ``colorspace`` OR ``p`` OR ``vmax`` """ handles = [] epoch = layers[0] xdim = epoch.get_dim(x) if epoch.ndim == 2: xdim_i = epoch.dimnames.index(x) ydim_i = {1:0, 0:1}[xdim_i] y = epoch.dimnames[ydim_i] else: err = ("Need 2 dimensions, got %i" % epoch.ndim) raise ValueError(err) ydim = epoch.get_dim(y) if y == 'sensor': ydim = _dta.var(np.arange(len(ydim)), y) map_kwargs = {'extent': [xdim[0], xdim[-1], ydim[0], ydim[-1]], 'aspect': 'auto'} # plot for l in layers: h = _plt_im_array(ax, l, dims=(y, x), **map_kwargs) handles.append(h) if xlabel: if xlabel is True: xlabel = xdim.name ax.set_xlabel(xlabel) if ylabel: if ylabel is True: ylabel = ydim.name ax.set_ylabel(ylabel) # x-ticks tickstart = math.ceil(xdim[0] / tick_spacing) * tick_spacing tickend = xdim[-1] + tick_spacing / 1e4 ticklabels = np.arange(tickstart, tickend, tick_spacing) ax.xaxis.set_ticks(ticklabels) ax.x_fmt = "t = %.3f s" # y-ticks if y == 'sensor': # make sure y-ticklabels are all integers locs = ax.yaxis.get_ticklocs() if any(locs != locs.round()): idx = np.where(locs == locs.round())[0] locs = locs[idx] labels = map(lambda x: str(int(x)), locs) ax.yaxis.set_ticks(locs) ax.yaxis.set_ticklabels(labels) # title if title is None: if plt.rcParams['text.usetex']: title = fmtxt.texify(epoch.name) else: title = epoch.name ax.set_title(title) return handles