def test_raw_reject(): """Test raw data getter with annotation reject.""" info = create_info(['a', 'b', 'c', 'd', 'e'], 100, ch_types='eeg') raw = RawArray(np.ones((5, 15000)), info) with warnings.catch_warnings(record=True): # one outside range raw.annotations = Annotations([2, 100, 105, 148], [2, 8, 5, 8], 'BAD') data = raw.get_data([0, 1, 3, 4], 100, 11200, 'omit') assert_array_equal(data.shape, (4, 9900)) # with orig_time and complete overlap raw = read_raw_fif(fif_fname) raw.annotations = Annotations([44, 47, 48], [1, 3, 1], 'BAD', raw.info['meas_date']) data, times = raw.get_data(range(10), 0, 6000, 'omit', True) assert_array_equal(data.shape, (10, 4799)) assert_equal(times[-1], raw.times[5999]) assert_array_equal(data[:, -100:], raw[:10, 5900:6000][0]) data, times = raw.get_data(range(10), 0, 6000, 'NaN', True) assert_array_equal(data.shape, (10, 6000)) assert_equal(times[-1], raw.times[5999]) assert_true(np.isnan(data[:, 313:613]).all()) # 1s -2s assert_true(not np.isnan(data[:, 614].any())) assert_array_equal(data[:, -100:], raw[:10, 5900:6000][0]) assert_array_equal(raw.get_data(), raw[:][0]) # Test _sync_onset times = [10, -88, 190] onsets = _sync_onset(raw, times) assert_array_almost_equal(onsets, times - raw.first_samp / raw.info['sfreq']) assert_array_almost_equal(times, _sync_onset(raw, onsets, True))
def test_annotations(): """Test annotation class.""" raw = Raw(fif_fname) onset = np.array(range(10)) duration = np.ones(10) + raw.first_samp description = np.repeat('test', 10) dt = datetime.utcnow() meas_date = raw.info['meas_date'] # Test time shifts. for orig_time in [None, dt, meas_date[0], meas_date]: annot = Annotations(onset, duration, description, orig_time) assert_raises(ValueError, Annotations, onset, duration, description[:9]) assert_raises(ValueError, Annotations, [onset, 1], duration, description) assert_raises(ValueError, Annotations, onset, [duration, 1], description) # Test combining annotations with concatenate_raws annot = Annotations(onset, duration, description, dt) sfreq = raw.info['sfreq'] raw2 = raw.copy() raw2.annotations = annot concatenate_raws([raw, raw2]) assert_array_equal(annot.onset, raw.annotations.onset) assert_array_equal(annot.duration, raw.annotations.duration) raw2.annotations = Annotations(onset, duration * 2, description, None) last_samp = raw.last_samp - 1 concatenate_raws([raw, raw2]) onsets = np.concatenate([onset, onset + (last_samp - raw.first_samp) / sfreq]) assert_array_equal(raw.annotations.onset, onsets) assert_array_equal(raw.annotations.onset[:10], onset) assert_array_equal(raw.annotations.duration[:10], duration) assert_array_equal(raw.annotations.duration[10:], duration * 2) assert_array_equal(raw.annotations.description, np.repeat('test', 20))
def test_raw_reject(): """Test raw data getter with annotation reject.""" sfreq = 100. info = create_info(['a', 'b', 'c', 'd', 'e'], sfreq, ch_types='eeg') raw = RawArray(np.ones((5, 15000)), info) with warnings.catch_warnings(record=True): # one outside range raw.set_annotations( Annotations([2, 100, 105, 148], [2, 8, 5, 8], 'BAD')) data, times = raw.get_data( [0, 1, 3, 4], 100, 11200, # 1-112 sec 'omit', return_times=True) bad_times = np.concatenate([ np.arange(200, 400), np.arange(10000, 10800), np.arange(10500, 11000) ]) expected_times = np.setdiff1d(np.arange(100, 11200), bad_times) / sfreq assert_allclose(times, expected_times) # with orig_time and complete overlap raw = read_raw_fif(fif_fname) t_0 = raw.first_samp / raw.info['sfreq'] raw.set_annotations( Annotations([t_0 + 1, t_0 + 4, t_0 + 5], [1, 3, 1], 'BAD', raw.info['meas_date'])) t_stop = 18. assert raw.times[-1] > t_stop n_stop = int(round(t_stop * raw.info['sfreq'])) n_drop = int(round(4 * raw.info['sfreq'])) assert len(raw.times) >= n_stop data, times = raw.get_data(range(10), 0, n_stop, 'omit', True) assert data.shape == (10, n_stop - n_drop) assert times[-1] == raw.times[n_stop - 1] assert_array_equal(data[:, -100:], raw[:10, n_stop - 100:n_stop][0]) data, times = raw.get_data(range(10), 0, n_stop, 'NaN', True) assert_array_equal(data.shape, (10, n_stop)) assert times[-1] == raw.times[n_stop - 1] t_1, t_2 = raw.time_as_index([1, 2], use_rounding=True) assert np.isnan(data[:, t_1:t_2]).all() # 1s -2s assert not np.isnan(data[:, :t_1].any()) assert not np.isnan(data[:, t_2:].any()) assert_array_equal(data[:, -100:], raw[:10, n_stop - 100:n_stop][0]) assert_array_equal(raw.get_data(), raw[:][0]) # Test _sync_onset times = [10, -88, 190] onsets = _sync_onset(raw, times) assert_array_almost_equal(onsets, times - raw.first_samp / raw.info['sfreq']) assert_array_almost_equal(times, _sync_onset(raw, onsets, True))
def test_annotations(): """Test annotation class.""" raw = read_raw_fif(fif_fname) onset = np.array(range(10)) duration = np.ones(10) description = np.repeat('test', 10) dt = datetime.utcnow() meas_date = raw.info['meas_date'] # Test time shifts. for orig_time in [None, dt, meas_date[0], meas_date]: annot = Annotations(onset, duration, description, orig_time) assert_raises(ValueError, Annotations, onset, duration, description[:9]) assert_raises(ValueError, Annotations, [onset, 1], duration, description) assert_raises(ValueError, Annotations, onset, [duration, 1], description) # Test combining annotations with concatenate_raws raw2 = raw.copy() orig_time = (meas_date[0] + meas_date[1] * 0.000001 + raw2.first_samp / raw2.info['sfreq']) annot = Annotations(onset, duration, description, orig_time) raw2.annotations = annot assert_array_equal(raw2.annotations.onset, onset) concatenate_raws([raw, raw2]) assert_array_almost_equal(onset + 20., raw.annotations.onset, decimal=2) assert_array_equal(annot.duration, raw.annotations.duration) assert_array_equal(raw.annotations.description, np.repeat('test', 10)) # Test combining with RawArray and orig_times data = np.random.randn(2, 1000) * 10e-12 sfreq = 100. info = create_info(ch_names=['MEG1', 'MEG2'], ch_types=['grad'] * 2, sfreq=sfreq) info['meas_date'] = 0 raws = [] for i, fs in enumerate([1000, 100, 12]): raw = RawArray(data.copy(), info, first_samp=fs) ants = Annotations([1., 2.], [.5, .5], 'x', fs / sfreq) raw.annotations = ants raws.append(raw) raw = concatenate_raws(raws) assert_array_equal(raw.annotations.onset, [1., 2., 11., 12., 21., 22.]) raw.annotations.delete(2) assert_array_equal(raw.annotations.onset, [1., 2., 12., 21., 22.]) raw.annotations.append(5, 1.5, 'y') assert_array_equal(raw.annotations.onset, [1., 2., 12., 21., 22., 5]) assert_array_equal(raw.annotations.duration, [.5, .5, .5, .5, .5, 1.5]) assert_array_equal(raw.annotations.description, ['x', 'x', 'x', 'x', 'x', 'y'])
def test_annotation_omit(): """Test raw.get_data with annotations.""" data = np.concatenate([np.ones((1, 1000)), 2 * np.ones((1, 1000))], -1) info = create_info(1, 1000., 'eeg') raw = RawArray(data, info) raw.annotations = Annotations([0.5], [1], ['bad']) expected = raw[0][0] assert_allclose(raw.get_data(reject_by_annotation=None), expected) # nan expected[0, 500:1500] = np.nan assert_allclose(raw.get_data(reject_by_annotation='nan'), expected) got = np.concatenate([ raw.get_data(start=start, stop=stop, reject_by_annotation='nan') for start, stop in ((0, 1000), (1000, 2000)) ], -1) assert_allclose(got, expected) # omit expected = expected[:, np.isfinite(expected[0])] assert_allclose(raw.get_data(reject_by_annotation='omit'), expected) got = np.concatenate([ raw.get_data(start=start, stop=stop, reject_by_annotation='omit') for start, stop in ((0, 1000), (1000, 2000)) ], -1) assert_allclose(got, expected) assert_raises(ValueError, raw.get_data, reject_by_annotation='foo')
def test_save(): """ Test saving raw""" tempdir = _TempDir() raw = Raw(fif_fname, preload=False) # can't write over file being read assert_raises(ValueError, raw.save, fif_fname) raw = Raw(fif_fname, preload=True) # can't overwrite file without overwrite=True assert_raises(IOError, raw.save, fif_fname) # test abspath support and annotations annot = Annotations([10], [10], ['test'], raw.info['meas_date']) raw.annotations = annot new_fname = op.join(op.abspath(op.curdir), 'break-raw.fif') raw.save(op.join(tempdir, new_fname), overwrite=True) new_raw = Raw(op.join(tempdir, new_fname), preload=False) assert_raises(ValueError, new_raw.save, new_fname) assert_array_equal(annot.onset, new_raw.annotations.onset) assert_array_equal(annot.duration, new_raw.annotations.duration) assert_array_equal(annot.description, new_raw.annotations.description) assert_equal(annot.orig_time, new_raw.annotations.orig_time) # make sure we can overwrite the file we loaded when preload=True new_raw = Raw(op.join(tempdir, new_fname), preload=True) new_raw.save(op.join(tempdir, new_fname), overwrite=True) os.remove(new_fname)
def test_annotations_crop(): """Test basic functionality of annotation crop.""" onset = np.arange(1, 10) duration = np.full_like(onset, 10) description = ["yy"] * onset.shape[0] a = Annotations(onset=onset, duration=duration, description=description, orig_time=0) # cropping window larger than annotations --> do not modify a_ = a.copy().crop(tmin=0, tmax=42) assert_array_equal(a_.onset, a.onset) assert_array_equal(a_.duration, a.duration) # cropping with left shifted window with pytest.warns(None) as w: a_ = a.copy().crop(tmin=0, tmax=4.2) assert_array_equal(a_.onset, [1., 2., 3., 4.]) assert_allclose(a_.duration, [3.2, 2.2, 1.2, 0.2]) assert len(w) == 0 # cropping with right shifted window with pytest.warns(None) as w: a_ = a.copy().crop(tmin=17.8, tmax=22) assert_array_equal(a_.onset, [17.8, 17.8]) assert_allclose(a_.duration, [0.2, 1.2]) assert len(w) == 0 # cropping with centered small window a_ = a.copy().crop(tmin=11, tmax=12) assert_array_equal(a_.onset, [11, 11, 11, 11, 11, 11, 11, 11, 11]) assert_array_equal(a_.duration, [0, 1, 1, 1, 1, 1, 1, 1, 1]) # cropping with out-of-bounds window with pytest.warns(None) as w: a_ = a.copy().crop(tmin=42, tmax=100) assert_array_equal(a_.onset, []) assert_array_equal(a_.duration, []) assert len(w) == 0 # test error raising with pytest.raises(ValueError, match='tmax should be greater than tmin'): a.copy().crop(tmin=42, tmax=0) with pytest.raises(ValueError, match='tmin should be positive'): a.copy().crop(tmin=-10, tmax=0) # test warnings with pytest.warns(RuntimeWarning, match='Omitted .* were outside'): a.copy().crop(tmin=42, tmax=100, emit_warning=True) with pytest.warns(RuntimeWarning, match='Limited .* expanding outside'): a.copy().crop(tmin=0, tmax=12, emit_warning=True)
def test_annotation_concat(): """Test if two Annotations objects can be concatenated.""" a = Annotations([1, 2, 3], [5, 5, 8], ["a", "b", "c"]) b = Annotations([11, 12, 13], [1, 2, 2], ["x", "y", "z"]) # test + operator (does not modify a or b) c = a + b assert_array_equal(c.onset, [1, 2, 3, 11, 12, 13]) assert_array_equal(c.duration, [5, 5, 8, 1, 2, 2]) assert_array_equal(c.description, ["a", "b", "c", "x", "y", "z"]) assert_equal(len(a), 3) assert_equal(len(b), 3) assert_equal(len(c), 6) # test += operator (modifies a in place) a += b assert_array_equal(a.onset, [1, 2, 3, 11, 12, 13]) assert_array_equal(a.duration, [5, 5, 8, 1, 2, 2]) assert_array_equal(a.description, ["a", "b", "c", "x", "y", "z"]) assert_equal(len(a), 6) assert_equal(len(b), 3)
def annotate_motion(raw, pos, thr=0.01): """Find and annotate periods of high HPI distance w.r.t the median HPI pos and readjust trans matrix dev->head - written originally by Luke Bloy""" annot = Annotations([], [], []) info = raw.info time = pos[:, 0] quats = pos[:, 1:7] # Get static head pos from file, used to convert quat to cartesian chpi_locs_dev = sorted([d for d in info['hpi_results'][-1] ['dig_points']], key=lambda x: x['ident']) chpi_locs_dev = np.array([d['r'] for d in chpi_locs_dev]) # chpi_locs_dev[0]-> LPA, chpi_locs_dev[1]-> NASION, chpi_locs_dev[2]-> RPA # Get head pos changes during recording chpi_mov_head = np.array([_apply_quat(quat, chpi_locs_dev, move=True) for quat in quats]) # get median position across all recording chpi_mov_head_f = chpi_mov_head.reshape([-1, 9]) # always 9 chans chpi_med_head_tmp = np.median(chpi_mov_head_f, axis=0).reshape([3, 3]) # get movement displacement from median hpi_disp = chpi_mov_head - np.tile(chpi_med_head_tmp, (len(time), 1, 1)) # get positions above threshold distance disp = np.sqrt((hpi_disp ** 2).sum(axis=2)) disp_exes = np.any(disp > thr, axis=1) # Get median head pos during recording under threshold distance weights = np.append(time[1:] - time[:-1], 0) weights[disp_exes] = 0 weights /= sum(weights) tmp_med_head = weighted_median(chpi_mov_head, weights) # Get closest real pos to estimated median hpi_disp_th = chpi_mov_head - np.tile(tmp_med_head, (len(time), 1, 1)) hpi_dist_th = np.sqrt((hpi_disp_th.reshape(-1, 9) ** 2).sum(axis=1)) chpi_median_pos = chpi_mov_head[hpi_dist_th.argmin(), :, :] # Compute displacements from final median head pos hpi_disp = chpi_mov_head - np.tile(chpi_median_pos, (len(time), 1, 1)) hpi_disp = np.sqrt((hpi_disp**2).sum(axis=-1)) art_mask_mov = np.any(hpi_disp > thr, axis=-1) # hpi_disp > thr why? annot += _annotations_from_mask(time, art_mask_mov, 'Bad-motion-dist>%0.3f' % thr) # Compute new dev->head transformation from median init_dev_head_t = _quaternion_align(info['dev_head_t']['from'], info['dev_head_t']['to'], chpi_locs_dev, chpi_median_pos) dev_head_t = init_dev_head_t return annot, hpi_disp, dev_head_t
def test_flat_bad_acq_skip(): """Test that acquisition skips are handled properly.""" # -- file with a couple of skip and flat channels -- raw = read_raw_fif(skip_fname, preload=True) annots, bads = annotate_amplitude(raw, flat=0) assert len(annots) == 0 assert bads == [ # MaxFilter finds the same 21 channels 'MEG%04d' % (int(num),) for num in '141 331 421 431 611 641 1011 1021 1031 1241 1421 ' '1741 1841 2011 2131 2141 2241 2531 2541 2611 2621'.split()] # -- overlap of flat segment with bad_acq_skip -- n_ch, n_times = 11, 1000 data = np.random.RandomState(0).randn(n_ch, n_times) assert not (np.diff(data, axis=-1) == 0).any() # nothing flat at first info = create_info(n_ch, 1000., 'eeg') raw = RawArray(data, info, first_samp=0) raw.info['bads'] = [raw.ch_names[-1]] bad_acq_skip = Annotations([0.5], [0.2], ['bad_acq_skip'], orig_time=None) raw.set_annotations(bad_acq_skip) # add flat channel overlapping with the left edge of bad_acq_skip raw_ = raw.copy() raw_._data[0, 400:600] = 0. annots, bads = annotate_amplitude(raw_, peak=None, flat=0, bad_percent=25) assert len(annots) == 1 assert len(bads) == 0 # check annotation instance assert annots[0]['description'] == 'BAD_flat' _check_annotation(raw_, annots[0], None, 0, 400, 499) # add flat channel overlapping with the right edge of bad_acq_skip raw_ = raw.copy() raw_._data[0, 600:800] = 0. annots, bads = annotate_amplitude(raw_, peak=None, flat=0, bad_percent=25) assert len(annots) == 1 assert len(bads) == 0 # check annotation instance assert annots[0]['description'] == 'BAD_flat' _check_annotation(raw_, annots[0], None, 0, 700, 799) # add flat channel overlapping entirely with bad_acq_skip raw_ = raw.copy() raw_._data[0, 200:800] = 0. annots, bads = annotate_amplitude(raw_, peak=None, flat=0, bad_percent=41) assert len(annots) == 2 assert len(bads) == 0 # check annotation instance annots = sorted(annots, key=lambda x: x['onset']) assert all(annot['description'] == 'BAD_flat' for annot in annots) _check_annotation(raw_, annots[0], None, 0, 200, 500) _check_annotation(raw_, annots[1], None, 0, 700, 799)
def test_raw_reject(): """Test raw data getter with annotation reject.""" info = create_info(['a', 'b', 'c', 'd', 'e'], 100, ch_types='eeg') raw = RawArray(np.ones((5, 15000)), info) raw.annotations = Annotations([2, 100, 105, 148], [2, 8, 5, 8], 'BAD') data = raw.get_data([0, 1, 3, 4], 100, 11200, 'omit') assert_array_equal(data.shape, (4, 9900)) # with orig_time and complete overlap raw = read_raw_fif(fif_fname) raw.annotations = Annotations([44, 47, 48], [1, 3, 1], 'BAD', raw.info['meas_date']) data, times = raw.get_data(range(10), 0, 6000, 'omit', True) assert_array_equal(data.shape, (10, 4799)) assert_equal(times[-1], raw.times[5999]) assert_array_equal(data[:, -100:], raw[:10, 5900:6000][0]) data, times = raw.get_data(range(10), 0, 6000, 'NaN', True) assert_array_equal(data.shape, (10, 6000)) assert_equal(times[-1], raw.times[5999]) assert_true(np.isnan(data[:, 313:613]).all()) # 1s -2s assert_true(not np.isnan(data[:, 614].any())) assert_array_equal(data[:, -100:], raw[:10, 5900:6000][0]) assert_array_equal(raw.get_data(), raw[:][0])
def _annotations_from_mask(times, art_mask, art_name): # make annotations - by Luke Bloy comps, num_comps = label(art_mask) onsets = [] durations = [] desc = [] n_times = len(times) for l in range(1, num_comps+1): l_idx = np.nonzero(comps == l)[0] onsets.append(times[l_idx[0]]) # duration is to the time after the last labeled time # or to the end of the times. if 1+l_idx[-1] < n_times: durations.append(times[1+l_idx[-1]] - times[l_idx[0]]) else: durations.append(times[l_idx[-1]] - times[l_idx[0]]) desc.append(art_name) return Annotations(onsets, durations, desc)
def read_annotations_besa_evt(evt_fname, time_0=0.0): """Read in evt file as annotations.""" seg_info = dict() with open(evt_fname, 'r') as fid: fid.readline() for line in fid.readlines(): parts = line.strip().split('\t') code = parts[1] time = time_0 + 1e-6 * float(parts[0].strip()) if code not in seg_info: seg_info[code] = [] seg_info[code].append(time) # build Annotations onsets = [] durations = [] desc = [] for code, t_list in seg_info.iteritems(): it = iter(t_list) for t_start in it: onsets.append(t_start) durations.append(next(it) - t_start) desc.append('besa_%s' % code) return Annotations(onsets, durations, desc)
def test_crop(): """Test cropping with annotations.""" raw = read_raw_fif(fif_fname) events = mne.find_events(raw) onset = events[events[:, 2] == 1, 0] / raw.info['sfreq'] duration = np.full_like(onset, 0.5) description = ['bad %d' % k for k in range(len(onset))] raw.annotations = mne.Annotations(onset, duration, description, orig_time=raw.info['meas_date']) split_time = raw.times[-1] / 2. + 2. split_idx = len(onset) // 2 + 1 raw_cropped_left = raw.copy().crop(0., split_time - 1. / raw.info['sfreq']) assert_array_equal(raw_cropped_left.annotations.description, raw.annotations.description[:split_idx]) assert_allclose(raw_cropped_left.annotations.duration, raw.annotations.duration[:split_idx]) assert_allclose(raw_cropped_left.annotations.onset, raw.annotations.onset[:split_idx]) raw_cropped_right = raw.copy().crop(split_time, None) assert_array_equal(raw_cropped_right.annotations.description, raw.annotations.description[split_idx:]) assert_allclose(raw_cropped_right.annotations.duration, raw.annotations.duration[split_idx:]) assert_allclose(raw_cropped_right.annotations.onset, raw.annotations.onset[split_idx:]) raw_concat = mne.concatenate_raws([raw_cropped_left, raw_cropped_right], verbose='debug') assert_allclose(raw_concat.times, raw.times) assert_allclose(raw_concat[:][0], raw[:][0], atol=1e-20) # Get rid of the boundary events raw_concat.annotations.delete(-1) raw_concat.annotations.delete(-1) # Ensure we annotations survive round-trip crop->concat assert_array_equal(raw_concat.annotations.description, raw.annotations.description) for attr in ('onset', 'duration'): assert_allclose(getattr(raw_concat.annotations, attr), getattr(raw.annotations, attr), err_msg='Failed for %s:' % (attr, )) raw.annotations = None # undo # Test concatenating annotations with and without orig_time. last_time = raw.last_samp / raw.info['sfreq'] raw2 = raw.copy() raw.annotations = Annotations([45.], [3], 'test', raw.info['meas_date']) raw2.annotations = Annotations([2.], [3], 'BAD', None) raw = concatenate_raws([raw, raw2]) raw.annotations.delete(-1) # remove boundary annotations raw.annotations.delete(-1) assert_array_almost_equal(raw.annotations.onset, [45., 2. + last_time], decimal=2) # Test IO tempdir = _TempDir() fname = op.join(tempdir, 'test-annot.fif') raw.annotations.save(fname) annot_read = read_annotations(fname) for attr in ('onset', 'duration', 'orig_time'): assert_allclose(getattr(annot_read, attr), getattr(raw.annotations, attr)) assert_array_equal(annot_read.description, raw.annotations.description) annot = Annotations((), (), ()) annot.save(fname) pytest.raises(IOError, read_annotations, fif_fname) # none in old raw annot = read_annotations(fname) assert isinstance(annot, Annotations) assert len(annot) == 0 # Test that empty annotations can be saved with an object fname = op.join(tempdir, 'test_raw.fif') raw.annotations = annot raw.save(fname) raw_read = read_raw_fif(fname) assert isinstance(raw_read.annotations, Annotations) assert len(raw_read.annotations) == 0 raw.annotations = None raw.save(fname, overwrite=True) raw_read = read_raw_fif(fname) assert raw_read.annotations is None
def test_annotation_filtering(): """Test that annotations work properly with filtering.""" # Create data with just a DC component data = np.ones((1, 1000)) info = create_info(1, 1000., 'eeg') raws = [RawArray(data * (ii + 1), info) for ii in range(4)] kwargs_pass = dict(l_freq=None, h_freq=50., fir_design='firwin') kwargs_stop = dict(l_freq=50., h_freq=None, fir_design='firwin') # lowpass filter, which should not modify the data raws_pass = [raw.copy().filter(**kwargs_pass) for raw in raws] # highpass filter, which should zero it out raws_stop = [raw.copy().filter(**kwargs_stop) for raw in raws] # concat the original and the filtered segments raws_concat = concatenate_raws([raw.copy() for raw in raws]) raws_zero = raws_concat.copy().apply_function(lambda x: x * 0) raws_pass_concat = concatenate_raws(raws_pass) raws_stop_concat = concatenate_raws(raws_stop) # make sure we did something reasonable with our individual-file filtering assert_allclose(raws_concat[0][0], raws_pass_concat[0][0], atol=1e-14) assert_allclose(raws_zero[0][0], raws_stop_concat[0][0], atol=1e-14) # ensure that our Annotations cut up the filtering properly raws_concat_pass = raws_concat.copy().filter(skip_by_annotation='edge', **kwargs_pass) assert_allclose(raws_concat[0][0], raws_concat_pass[0][0], atol=1e-14) raws_concat_stop = raws_concat.copy().filter(skip_by_annotation='edge', **kwargs_stop) assert_allclose(raws_zero[0][0], raws_concat_stop[0][0], atol=1e-14) # one last test: let's cut out a section entirely: # here the 1-3 second window should be skipped raw = raws_concat.copy() raw.annotations.append(1., 2., 'foo') raw.filter(l_freq=50., h_freq=None, fir_design='firwin', skip_by_annotation='foo') # our filter will zero out anything not skipped: mask = np.concatenate((np.zeros(1000), np.ones(2000), np.zeros(1000))) expected_data = raws_concat[0][0][0] * mask assert_allclose(raw[0][0][0], expected_data, atol=1e-14) # Let's try another one raw = raws[0].copy() raw.annotations = Annotations([0.], [0.5], ['BAD_ACQ_SKIP']) my_data, times = raw.get_data(reject_by_annotation='omit', return_times=True) assert_allclose(times, raw.times[500:]) assert my_data.shape == (1, 500) raw_filt = raw.copy().filter(skip_by_annotation='bad_acq_skip', **kwargs_stop) expected = data.copy() expected[:, 500:] = 0 assert_allclose(raw_filt[:][0], expected, atol=1e-14) raw = raws[0].copy() raw.annotations = Annotations([0.5], [0.5], ['BAD_ACQ_SKIP']) my_data, times = raw.get_data(reject_by_annotation='omit', return_times=True) assert_allclose(times, raw.times[:500]) assert my_data.shape == (1, 500) raw_filt = raw.copy().filter(skip_by_annotation='bad_acq_skip', **kwargs_stop) expected = data.copy() expected[:, :500] = 0 assert_allclose(raw_filt[:][0], expected, atol=1e-14)
def test_basics(): """Test annotation class.""" raw = read_raw_fif(fif_fname) assert raw.annotations is None pytest.raises(IOError, read_annotations, fif_fname) onset = np.array(range(10)) duration = np.ones(10) description = np.repeat('test', 10) dt = datetime.utcnow() meas_date = raw.info['meas_date'] # Test time shifts. for orig_time in [None, dt, meas_date[0], meas_date]: annot = Annotations(onset, duration, description, orig_time) pytest.raises(ValueError, Annotations, onset, duration, description[:9]) pytest.raises(ValueError, Annotations, [onset, 1], duration, description) pytest.raises(ValueError, Annotations, onset, [duration, 1], description) # Test combining annotations with concatenate_raws raw2 = raw.copy() delta = raw.times[-1] + 1. / raw.info['sfreq'] orig_time = (meas_date[0] + meas_date[1] * 1e-6 + raw2.first_samp / raw2.info['sfreq']) annot = Annotations(onset, duration, description, orig_time) assert ' segments' in repr(annot) raw2.annotations = annot assert_array_equal(raw2.annotations.onset, onset) concatenate_raws([raw, raw2]) raw.annotations.delete(-1) # remove boundary annotations raw.annotations.delete(-1) assert_allclose(onset + delta, raw.annotations.onset, rtol=1e-5) assert_array_equal(annot.duration, raw.annotations.duration) assert_array_equal(raw.annotations.description, np.repeat('test', 10)) # Test combining with RawArray and orig_times data = np.random.randn(2, 1000) * 10e-12 sfreq = 100. info = create_info(ch_names=['MEG1', 'MEG2'], ch_types=['grad'] * 2, sfreq=sfreq) info['meas_date'] = np.pi raws = [] for first_samp in [12300, 100, 12]: raw = RawArray(data.copy(), info, first_samp=first_samp) ants = Annotations([1., 2.], [.5, .5], 'x', np.pi + first_samp / sfreq) raw.annotations = ants raws.append(raw) raw = RawArray(data.copy(), info) raw.annotations = Annotations([1.], [.5], 'x', None) raws.append(raw) raw = concatenate_raws(raws, verbose='debug') boundary_idx = np.where(raw.annotations.description == 'BAD boundary')[0] assert len(boundary_idx) == 3 raw.annotations.delete(boundary_idx) boundary_idx = np.where(raw.annotations.description == 'EDGE boundary')[0] assert len(boundary_idx) == 3 raw.annotations.delete(boundary_idx) assert_array_equal(raw.annotations.onset, [1., 2., 11., 12., 21., 22., 31.]) raw.annotations.delete(2) assert_array_equal(raw.annotations.onset, [1., 2., 12., 21., 22., 31.]) raw.annotations.append(5, 1.5, 'y') assert_array_equal(raw.annotations.onset, [1., 2., 12., 21., 22., 31., 5]) assert_array_equal(raw.annotations.duration, [.5, .5, .5, .5, .5, .5, 1.5]) assert_array_equal(raw.annotations.description, ['x', 'x', 'x', 'x', 'x', 'x', 'y'])
def test_annotations(): """Test annotation class.""" raw = read_raw_fif(fif_fname) assert raw.annotations is None assert_raises(ValueError, read_annotations, fif_fname) onset = np.array(range(10)) duration = np.ones(10) description = np.repeat('test', 10) dt = datetime.utcnow() meas_date = raw.info['meas_date'] # Test time shifts. for orig_time in [None, dt, meas_date[0], meas_date]: annot = Annotations(onset, duration, description, orig_time) assert_raises(ValueError, Annotations, onset, duration, description[:9]) assert_raises(ValueError, Annotations, [onset, 1], duration, description) assert_raises(ValueError, Annotations, onset, [duration, 1], description) # Test combining annotations with concatenate_raws raw2 = raw.copy() orig_time = (meas_date[0] + meas_date[1] * 0.000001 + raw2.first_samp / raw2.info['sfreq']) annot = Annotations(onset, duration, description, orig_time) assert_true(' segments' in repr(annot)) raw2.annotations = annot assert_array_equal(raw2.annotations.onset, onset) concatenate_raws([raw, raw2]) raw.annotations.delete(-1) # remove boundary annotations raw.annotations.delete(-1) assert_array_almost_equal(onset + 20., raw.annotations.onset, decimal=2) assert_array_equal(annot.duration, raw.annotations.duration) assert_array_equal(raw.annotations.description, np.repeat('test', 10)) # Test combining with RawArray and orig_times data = np.random.randn(2, 1000) * 10e-12 sfreq = 100. info = create_info(ch_names=['MEG1', 'MEG2'], ch_types=['grad'] * 2, sfreq=sfreq) info['meas_date'] = 0 raws = [] for i, fs in enumerate([12300, 100, 12]): raw = RawArray(data.copy(), info, first_samp=fs) ants = Annotations([1., 2.], [.5, .5], 'x', fs / sfreq) raw.annotations = ants raws.append(raw) raw = RawArray(data.copy(), info) raw.annotations = Annotations([1.], [.5], 'x', None) raws.append(raw) raw = concatenate_raws(raws) boundary_idx = np.where(raw.annotations.description == 'BAD boundary')[0] assert_equal(len(boundary_idx), 3) raw.annotations.delete(boundary_idx) boundary_idx = np.where(raw.annotations.description == 'EDGE boundary')[0] assert_equal(len(boundary_idx), 3) raw.annotations.delete(boundary_idx) assert_array_equal(raw.annotations.onset, [1., 2., 11., 12., 21., 22., 31.]) raw.annotations.delete(2) assert_array_equal(raw.annotations.onset, [1., 2., 12., 21., 22., 31.]) raw.annotations.append(5, 1.5, 'y') assert_array_equal(raw.annotations.onset, [1., 2., 12., 21., 22., 31., 5]) assert_array_equal(raw.annotations.duration, [.5, .5, .5, .5, .5, .5, 1.5]) assert_array_equal(raw.annotations.description, ['x', 'x', 'x', 'x', 'x', 'x', 'y']) # Test concatenating annotations with and without orig_time. raw = read_raw_fif(fif_fname) last_time = raw.last_samp / raw.info['sfreq'] raw2 = raw.copy() raw.annotations = Annotations([45.], [3], 'test', raw.info['meas_date']) raw2.annotations = Annotations([2.], [3], 'BAD', None) raw = concatenate_raws([raw, raw2]) raw.annotations.delete(-1) # remove boundary annotations raw.annotations.delete(-1) assert_array_almost_equal(raw.annotations.onset, [45., 2. + last_time], decimal=2) # Test IO tempdir = _TempDir() fname = op.join(tempdir, 'test-annot.fif') raw.annotations.save(fname) annot_read = read_annotations(fname) for attr in ('onset', 'duration', 'orig_time'): assert_allclose(getattr(annot_read, attr), getattr(raw.annotations, attr)) assert_array_equal(annot_read.description, raw.annotations.description)
def annotate_motion_artifacts(raw, pos, disp_thr=0.01, velo_thr=0.03, gof_thr=0.99, return_stat_raw=False): """Find and annotate periods of high HPI velocity and high HPI distance.""" annot = Annotations([], [], []) info = raw.info # grab initial cHPI locations # point sorted in hpi_results are in mne device coords chpi_locs_dev = sorted([d for d in info['hpi_results'][-1]['dig_points']], key=lambda x: x['ident']) chpi_locs_dev = np.array([d['r'] for d in chpi_locs_dev]) # chpi_locs_dev[0] -> LPA # chpi_locs_dev[1] -> NASION # chpi_locs_dev[2] -> RPA chpi_static_head = apply_trans(info['dev_head_t'], chpi_locs_dev) time = pos[:, 0] n_hpi = chpi_static_head.shape[0] quats = pos[:, 1:7] chpi_moving_head = np.array( [_apply_quat(quat, chpi_locs_dev, move=True) for quat in quats]) # compute displacements hpi_disp = chpi_moving_head - np.tile(chpi_static_head, (len(time), 1, 1)) hpi_disp = np.sqrt((hpi_disp**2).sum(axis=-1)) # compute velocities hpi_velo = chpi_moving_head[1:, :, :] - chpi_moving_head[:-1, :, :] hpi_velo = np.sqrt((hpi_velo**2).sum(axis=-1)) hpi_velo /= np.tile(time[1:] - time[:-1], (n_hpi, 1)).transpose() hpi_velo = np.concatenate((np.zeros((1, n_hpi)), hpi_velo), axis=0) if disp_thr is not None: art_mask = hpi_disp > disp_thr annot += _annotations_from_mask(time, art_mask, 'Bad-motion-dist>%0.3f' % disp_thr) if velo_thr is not None: art_mask = hpi_velo > velo_thr annot += _annotations_from_mask(time, art_mask, 'Bad-motion-velo>%0.3f' % velo_thr) if gof_thr is not None: art_mask = pos[:, 7] <= gof_thr annot += _annotations_from_mask(time, art_mask, 'Bad-chpi_gof>%0.3f' % gof_thr) tmp = 1000 * hpi_disp.max(axis=0) _fmt = '\tHPI00 - %0.1f' for i in range(1, n_hpi): _fmt += '\n\tHPI%02d' % (i) + ' - %0.1f' logger.info('CHPI MAX Displacments (mm):') logger.info(_fmt % tuple(tmp)) tmp = 1000 * hpi_velo.max(axis=0) logger.info('CHPI Velocity Displacments (mm/sec):') logger.info(_fmt % tuple(tmp)) raw_hpi = None if return_stat_raw: n_times = len(raw.times) # build full time data arrays start_idx = raw.time_as_index(time, use_rounding=True) end_idx = raw.time_as_index(np.append(time[1:], raw.times[-1]), use_rounding=True) data_pos = np.zeros((2 * n_hpi, n_times)) for t_0, t_1, disp_val, velo_val in zip(start_idx, end_idx, hpi_disp, hpi_velo): t_slice = slice(t_0, t_1) data_pos[:n_hpi, t_slice] = np.tile(disp_val, (t_1 - t_0, 1)).T data_pos[n_hpi:, t_slice] = np.tile(velo_val, (t_1 - t_0, 1)).T ch_names = [] ch_names_ = [] for i in range(n_hpi): ch_names.append('HPI%02d_disp_pos' % i) ch_names_.append('HPI%02d_velo_pos' % i) ch_names.extend(ch_names_) # build raw object! info = create_info(ch_names=ch_names, ch_types=np.repeat('misc', len(ch_names)), sfreq=raw.info['sfreq']) raw_hpi = RawArray(data_pos, info) return annot, raw_hpi