def raw_factory(meas_date): raw = RawArray(data=np.empty((10, 10)), info=create_info(ch_names=10, sfreq=10.), first_samp=10) raw.set_meas_date(meas_date) raw.set_annotations(annotations=Annotations( onset=[.5], duration=[.2], description='dummy', orig_time=None)) return raw
def test_annotate_flat(meas_date, first_samp): """Test marking flat segments.""" # Test if ECG analysis will work on data that is not preloaded 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') # test first_samp != for gh-6295 raw = RawArray(data, info, first_samp=first_samp) raw.info['bads'] = [raw.ch_names[-1]] raw.set_meas_date(meas_date) # # First make a channel flat the whole time # raw_0 = raw.copy() raw_0._data[0] = 0. for kwargs, bads, want_times in [ # Anything < 1 will mark spatially (dict(bad_percent=100.), [], 0), (dict(bad_percent=99.9), [raw.ch_names[0]], n_times), (dict(), [raw.ch_names[0]], n_times) ]: # default (1) raw_time = raw_0.copy() annot, got_bads = annotate_flat(raw_0, verbose='debug', **kwargs) assert annot.orig_time == raw.info["meas_date"] assert got_bads == bads raw_time.set_annotations(raw_time.annotations + annot) raw_time.info['bads'] += got_bads n_good_times = raw_time.get_data(reject_by_annotation='omit').shape[1] assert n_good_times == want_times # # Now make a channel flat for 20% of the time points # raw_0 = raw.copy() n_good_times = int(round(0.8 * n_times)) raw_0._data[0, n_good_times:] = 0. threshold = 100 * (n_times - n_good_times) / n_times for kwargs, bads, want_times in [ # Should change behavior at bad_percent=20 (dict(bad_percent=100), [], n_good_times), (dict(bad_percent=threshold), [], n_good_times), (dict(bad_percent=threshold - 1e-5), [raw.ch_names[0]], n_times), (dict(), [raw.ch_names[0]], n_times) ]: annot, got_bads = annotate_flat(raw_0, verbose='debug', **kwargs) assert got_bads == bads raw_time = raw_0.copy() raw_time.set_annotations(raw_time.annotations + annot) raw_time.info['bads'] += got_bads n_good_times = raw_time.get_data(reject_by_annotation='omit').shape[1] assert n_good_times == want_times with pytest.raises(TypeError, match='must be an instance of BaseRaw'): annotate_flat(0.) with pytest.raises(ValueError, match='not convert string to float'): annotate_flat(raw, 'x')
def test_negative_meas_dates(windows_like_datetime): """Test meas_date previous to 1970.""" # Regression test for gh-6621 raw = RawArray(data=np.empty((1, 1), dtype=np.float64), info=create_info(ch_names=1, sfreq=1.)) raw.set_meas_date((-908196946, 988669)) raw.set_annotations(Annotations(description='foo', onset=[0], duration=[0], orig_time=None)) events, _ = events_from_annotations(raw) assert events[:, 0] == 0
def test_time_as_index_ref(offset, origin): """Test indexing of raw times.""" info = create_info(ch_names=10, sfreq=10.) raw = RawArray(data=np.empty((10, 10)), info=info, first_samp=10) raw.set_meas_date(1) relative_times = raw.times inds = raw.time_as_index(relative_times + offset, use_rounding=True, origin=origin) assert_array_equal(inds, np.arange(raw.n_times))
def test_annotate_amplitude_multiple_ch_types(meas_date, first_samp): """Test cases with several channel types.""" 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'] * 3 + ['mag'] * 2 + ['grad'] * 4 + ['eeg'] * 2) # from annotate_flat: test first_samp != for gh-6295 raw = RawArray(data, info, first_samp=first_samp) raw.info['bads'] = [raw.ch_names[-1]] raw.set_meas_date(meas_date) # -- 2 channel types both to annotate -- raw_ = raw.copy() raw_._data[1, 800:] = 0. raw_._data[5, :200] = np.arange(0, 200 * 10, 10) raw_._data[5, 200:] += raw_._data[5, 199] # add offset for next samples annots, bads = annotate_amplitude(raw_, peak=5, flat=0, bad_percent=50) assert len(annots) == 2 assert len(bads) == 0 # check annotation instance assert all(annot['description'] in ('BAD_flat', 'BAD_peak') for annot in annots) for annot in annots: start_idx = 0 if annot['description'] == 'BAD_peak' else 800 stop_idx = 199 if annot['description'] == 'BAD_peak' else -1 _check_annotation(raw_, annot, meas_date, first_samp, start_idx, stop_idx) # -- 2 channel types, one flat picked, one not picked -- raw_ = raw.copy() raw_._data[1, 800:] = 0. raw_._data[5, :200] = np.arange(0, 200 * 10, 10) raw_._data[5, 200:] += raw_._data[5, 199] # add offset for next samples annots, bads = annotate_amplitude(raw_, peak=5, flat=0, bad_percent=50, picks='eeg') assert len(annots) == 1 assert len(bads) == 0 # check annotation instance _check_annotation(raw_, annots[0], meas_date, first_samp, 800, -1) assert annots[0]['description'] == 'BAD_flat' # -- 2 channel types, one flat, one not picked, reverse -- raw_ = raw.copy() raw_._data[1, 800:] = 0. raw_._data[5, :200] = np.arange(0, 200 * 10, 10) raw_._data[5, 200:] += raw_._data[5, 199] # add offset for next samples annots, bads = annotate_amplitude(raw_, peak=5, flat=0, bad_percent=50, picks='grad') assert len(annots) == 1 assert len(bads) == 0 # check annotation instance _check_annotation(raw_, annots[0], meas_date, first_samp, 0, 199) assert annots[0]['description'] == 'BAD_peak'
def test_annotate_amplitude_with_overlap(meas_date, first_samp): """Test cases with overlap between annotations.""" 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') # from annotate_flat: test first_samp != for gh-6295 raw = RawArray(data, info, first_samp=first_samp) raw.info['bads'] = [raw.ch_names[-1]] raw.set_meas_date(meas_date) # -- overlap between peak and flat -- raw_ = raw.copy() raw_._data[0, 800:] = 0. raw_._data[1, 700:900] = np.arange(0, 200 * 10, 10) raw_._data[1, 900:] += raw_._data[1, 899] # add offset for next samples annots, bads = annotate_amplitude(raw_, peak=5, flat=0, bad_percent=25) assert len(annots) == 2 assert len(bads) == 0 # check annotation instance assert all(annot['description'] in ('BAD_flat', 'BAD_peak') for annot in annots) for annot in annots: start_idx = 700 if annot['description'] == 'BAD_peak' else 800 stop_idx = 899 if annot['description'] == 'BAD_peak' else -1 _check_annotation(raw_, annot, meas_date, first_samp, start_idx, stop_idx) # -- overlap between peak and peak on same channel -- raw_ = raw.copy() raw_._data[0, 700:900] = np.arange(0, 200 * 10, 10) raw_._data[0, 800:] = np.arange(1000, 300 * 10, 10) annots, bads = annotate_amplitude(raw_, peak=5, flat=None, bad_percent=50) assert len(annots) == 1 assert len(bads) == 0 # check annotation instance assert annots[0]['description'] == 'BAD_peak' _check_annotation(raw_, annots[0], meas_date, first_samp, 700, -1) # -- overlap between flat and flat on different channel -- raw_ = raw.copy() raw_._data[0, 700:900] = 0. raw_._data[1, 800:] = 0. annots, bads = annotate_amplitude(raw_, peak=None, flat=0.01, bad_percent=50) assert len(annots) == 1 assert len(bads) == 0 # check annotation instance assert annots[0]['description'] == 'BAD_flat' _check_annotation(raw_, annots[0], meas_date, first_samp, 700, -1)
def test_integer_sfreq_edf(tmp_path): """Test saving a Raw array with integer sfreq to EDF.""" np.random.RandomState(12345) format = 'edf' info = create_info(['1', '2', '3'], sfreq=1000, ch_types=['eeg', 'eeg', 'stim']) data = np.random.random(size=(3, 1000)) * 1e-6 # include subject info and measurement date subject_info = dict(first_name='mne', last_name='python', birthday=(1992, 1, 20), sex=1, hand=3) info['subject_info'] = subject_info raw = RawArray(data, info) raw.set_meas_date(datetime.now(tz=timezone.utc)) temp_fname = op.join(str(tmp_path), f'test.{format}') raw.export(temp_fname) raw_read = read_raw_edf(temp_fname, preload=True) # stim channel should be dropped raw.drop_channels('3') assert raw.ch_names == raw_read.ch_names # only compare the original length, since extra zeros are appended orig_raw_len = len(raw) assert_array_almost_equal( raw.get_data(), raw_read.get_data()[:, :orig_raw_len], decimal=4) assert_allclose( raw.times, raw_read.times[:orig_raw_len], rtol=0, atol=1e-5) # export now by hard-coding physical range raw.export(temp_fname, physical_range=(-3200, 3200)) # include bad birthday that is non-EDF compliant bad_info = info.copy() bad_info['subject_info']['birthday'] = (1700, 1, 20) raw = RawArray(data, bad_info) with pytest.raises(RuntimeError, match='Setting patient birth date'): raw.export(temp_fname) # include bad measurement date that is non-EDF compliant raw = RawArray(data, info) meas_date = datetime(year=1984, month=1, day=1, tzinfo=timezone.utc) raw.set_meas_date(meas_date) with pytest.raises(RuntimeError, match='Setting start date time'): raw.export(temp_fname)
def test_allow_nan_durations(): """Deal with "n/a" strings in BIDS events with nan durations.""" raw = RawArray(data=np.empty([2, 10], dtype=np.float64), info=create_info(ch_names=2, sfreq=1.), first_samp=0) raw.set_meas_date(0) ons = [1, 2., 15., 17.] dus = [np.nan, 1., 0.5, np.nan] descriptions = ['A'] * 4 onsets = np.asarray(ons, dtype=float) durations = np.asarray(dus, dtype=float) annot = mne.Annotations(onset=onsets, duration=durations, description=descriptions) with pytest.warns(RuntimeWarning, match='Omitted 2 annotation'): raw.set_annotations(annot)
def _create_annotation_based_on_descr(description, annotation_start_sampl=0, duration=0, orig_time=0): """Create a raw object with annotations from descriptions. The returning raw object contains as many annotations as description given. All starting at `annotation_start_sampl`. """ # create dummy raw raw = RawArray(data=np.empty([10, 10], dtype=np.float64), info=create_info(ch_names=10, sfreq=1000.), first_samp=0) raw.set_meas_date(0) # create dummy annotations based on the descriptions onset = raw.times[annotation_start_sampl] onset_matching_desc = np.full_like(description, onset, dtype=type(onset)) duration_matching_desc = np.full_like(description, duration, dtype=type(duration)) annot = Annotations(description=description, onset=onset_matching_desc, duration=duration_matching_desc, orig_time=orig_time) if duration != 0: with pytest.warns(RuntimeWarning, match='Limited.*expanding outside'): # duration 0.1s is larger than the raw data expand raw.set_annotations(annot) else: raw.set_annotations(annot) # Make sure that set_annotations(annot) works assert all(raw.annotations.onset == onset) if duration != 0: expected_duration = (len(raw.times) / raw.info['sfreq']) - onset else: expected_duration = 0 _duration = raw.annotations.duration[0] assert _duration == approx(expected_duration) assert all(raw.annotations.duration == _duration) assert all(raw.annotations.description == description) return raw
def test_read_ctf_annotations(): """Test reading CTF marker file.""" EXPECTED_LATENCIES = np.array([ 5640, 7950, 9990, 12253, 14171, 16557, 18896, 20846, # noqa 22702, 24990, 26830, 28974, 30906, 33077, 34985, 36907, # noqa 38922, 40760, 42881, 45222, 47457, 49618, 51802, 54227, # noqa 56171, 58274, 60394, 62375, 64444, 66767, 68827, 71109, # noqa 73499, 75807, 78146, 80415, 82554, 84508, 86403, 88426, # noqa 90746, 92893, 94779, 96822, 98996, 99001, 100949, 103325, # noqa 105322, 107678, 109667, 111844, 113682, 115817, 117691, 119663, # noqa 121966, 123831, 126110, 128490, 130521, 132808, 135204, 137210, # noqa 139130, 141390, 143660, 145748, 147889, 150205, 152528, 154646, # noqa 156897, 159191, 161446, 163722, 166077, 168467, 170624, 172519, # noqa 174719, 176886, 179062, 181405, 183709, 186034, 188454, 190330, # noqa 192660, 194682, 196834, 199161, 201035, 203008, 204999, 207409, # noqa 209661, 211895, 213957, 216005, 218040, 220178, 222137, 224305, # noqa 226297, 228654, 230755, 232909, 235205, 237373, 239723, 241762, # noqa 243748, 245762, 247801, 250055, 251886, 254252, 256441, 258354, # noqa 260680, 263026, 265048, 267073, 269235, 271556, 273927, 276197, # noqa 278436, 280536, 282691, 284933, 287061, 288936, 290941, 293183, # noqa 295369, 297729, 299626, 301546, 303449, 305548, 307882, 310124, # noqa 312374, 314509, 316815, 318789, 320981, 322879, 324878, 326959, # noqa 329341, 331200, 331201, 333469, 335584, 337984, 340143, 342034, # noqa 344360, 346309, 348544, 350970, 353052, 355227, 357449, 359603, # noqa 361725, 363676, 365735, 367799, 369777, 371904, 373856, 376204, # noqa 378391, 380800, 382859, 385161, 387093, 389434, 391624, 393785, # noqa 396093, 398214, 400198, 402166, 404104, 406047, 408372, 410686, # noqa 413029, 414975, 416850, 418797, 420824, 422959, 425026, 427215, # noqa 429278, 431668 # noqa ]) - 1 # Fieldtrip has 1 sample difference with MNE raw = RawArray( data=np.empty((1, 432000), dtype=np.float64), info=create_info(ch_names=1, sfreq=1200.0)) raw.set_meas_date(read_raw_ctf(somato_fname).info['meas_date']) raw.set_annotations(read_annotations(somato_fname)) events, _ = events_from_annotations(raw) latencies = np.sort(events[:, 0]) assert_allclose(latencies, EXPECTED_LATENCIES, atol=1e-6)
def test_rawarray_edf(tmp_path): """Test saving a Raw array with integer sfreq to EDF.""" rng = np.random.RandomState(12345) format = 'edf' ch_types = [ 'eeg', 'eeg', 'stim', 'ecog', 'seeg', 'eog', 'ecg', 'emg', 'dbs', 'bio' ] ch_names = np.arange(len(ch_types)).astype(str).tolist() info = create_info(ch_names, sfreq=1000, ch_types=ch_types) data = rng.random(size=(len(ch_names), 1000)) * 1e-5 # include subject info and measurement date subject_info = dict(first_name='mne', last_name='python', birthday=(1992, 1, 20), sex=1, hand=3) info['subject_info'] = subject_info raw = RawArray(data, info) time_now = datetime.now() meas_date = datetime(year=time_now.year, month=time_now.month, day=time_now.day, hour=time_now.hour, minute=time_now.minute, second=time_now.second, tzinfo=timezone.utc) raw.set_meas_date(meas_date) temp_fname = op.join(str(tmp_path), f'test.{format}') raw.export(temp_fname, add_ch_type=True) raw_read = read_raw_edf(temp_fname, preload=True) # stim channel should be dropped raw.drop_channels('2') assert raw.ch_names == raw_read.ch_names # only compare the original length, since extra zeros are appended orig_raw_len = len(raw) assert_array_almost_equal(raw.get_data(), raw_read.get_data()[:, :orig_raw_len], decimal=4) assert_allclose(raw.times, raw_read.times[:orig_raw_len], rtol=0, atol=1e-5) # check channel types except for 'bio', which loses its type orig_ch_types = raw.get_channel_types() read_ch_types = raw_read.get_channel_types() assert_array_equal(orig_ch_types, read_ch_types) assert raw.info['meas_date'] == raw_read.info['meas_date'] # channel name can't be longer than 16 characters with the type added raw_bad = raw.copy() raw_bad.rename_channels({'1': 'abcdefghijklmnopqrstuvwxyz'}) with pytest.raises(RuntimeError, match='Signal label'), \ pytest.warns(RuntimeWarning, match='Data has a non-integer'): raw_bad.export(temp_fname) # include bad birthday that is non-EDF compliant bad_info = info.copy() bad_info['subject_info']['birthday'] = (1700, 1, 20) raw = RawArray(data, bad_info) with pytest.raises(RuntimeError, match='Setting patient birth date'): raw.export(temp_fname) # include bad measurement date that is non-EDF compliant raw = RawArray(data, info) meas_date = datetime(year=1984, month=1, day=1, tzinfo=timezone.utc) raw.set_meas_date(meas_date) with pytest.raises(RuntimeError, match='Setting start date time'): raw.export(temp_fname) # test that warning is raised if there are non-voltage based channels raw = RawArray(data, info) with pytest.warns(RuntimeWarning, match='The unit'): raw.set_channel_types({'9': 'hbr'}) with pytest.warns(RuntimeWarning, match='Non-voltage channels'): raw.export(temp_fname) # data should match up to the non-accepted channel raw_read = read_raw_edf(temp_fname, preload=True) orig_raw_len = len(raw) assert_array_almost_equal(raw.get_data()[:-1, :], raw_read.get_data()[:, :orig_raw_len], decimal=4) assert_allclose(raw.times, raw_read.times[:orig_raw_len], rtol=0, atol=1e-5) # the data should still match though raw_read = read_raw_edf(temp_fname, preload=True) raw.drop_channels('2') assert raw.ch_names == raw_read.ch_names orig_raw_len = len(raw) assert_array_almost_equal(raw.get_data(), raw_read.get_data()[:, :orig_raw_len], decimal=4) assert_allclose(raw.times, raw_read.times[:orig_raw_len], rtol=0, atol=1e-5)
def test_annotate_amplitude(meas_date, first_samp): """Test automatic annotation for segments based on peak-to-peak value.""" 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') # from annotate_flat: test first_samp != for gh-6295 raw = RawArray(data, info, first_samp=first_samp) raw.info['bads'] = [raw.ch_names[-1]] raw.set_meas_date(meas_date) # -- test bad channels spatial marking -- for perc, dur in itertools.product((5, 99.9, 100.), (0.005, 0.95, 0.99)): kwargs = dict(bad_percent=perc, min_duration=dur) # test entire channel flat raw_ = raw.copy() raw_._data[0] = 0. annots, bads = annotate_amplitude(raw_, peak=None, flat=0., **kwargs) assert len(annots) == 0 assert bads == ['0'] # test multiple channels flat raw_ = raw.copy() raw_._data[0] = 0. raw_._data[2] = 0. annots, bads = annotate_amplitude(raw_, peak=None, flat=0., **kwargs) assert len(annots) == 0 assert bads == ['0', '2'] # test entire channel drifting raw_ = raw.copy() raw_._data[0] = np.arange(0, raw.times.size * 10, 10) annots, bads = annotate_amplitude(raw_, peak=5, flat=None, **kwargs) assert len(annots) == 0 assert bads == ['0'] # test multiple channels drifting raw_ = raw.copy() raw_._data[0] = np.arange(0, raw.times.size * 10, 10) raw_._data[2] = np.arange(0, raw.times.size * 10, 10) annots, bads = annotate_amplitude(raw_, peak=5, flat=None, **kwargs) assert len(annots) == 0 assert bads == ['0', '2'] # -- test bad channels temporal marking -- # flat channel for the 20% last points n_good_times = int(round(0.8 * n_times)) raw_ = raw.copy() raw_._data[0, n_good_times:] = 0. for perc in (5, 20): annots, bads = annotate_amplitude(raw_, peak=None, flat=0., bad_percent=perc) assert len(annots) == 0 assert bads == ['0'] annots, bads = annotate_amplitude(raw_, peak=None, flat=0., bad_percent=20.1) assert len(annots) == 1 assert len(bads) == 0 # check annotation instance assert annots[0]['description'] == 'BAD_flat' _check_annotation(raw_, annots[0], meas_date, first_samp, n_good_times, -1) # test multiple channels flat and multiple channels drift raw_ = raw.copy() raw_._data[0, 800:] = 0. raw_._data[1, 850:950] = 0. raw_._data[2, :200] = np.arange(0, 200 * 10, 10) raw_._data[2, 200:] += raw_._data[2, 199] # add offset for next samples raw_._data[3, 50:150] = np.arange(0, 100 * 10, 10) raw_._data[3, 150:] += raw_._data[3, 149] # add offset for next samples for perc in (5, 10): annots, bads = annotate_amplitude(raw_, peak=5, flat=0., bad_percent=perc) assert len(annots) == 0 assert bads == ['0', '1', '2', '3'] for perc in (10.1, 20): annots, bads = annotate_amplitude(raw_, peak=5, flat=0., bad_percent=perc) assert len(annots) == 2 assert bads == ['0', '2'] # check annotation instance assert all(annot['description'] in ('BAD_flat', 'BAD_peak') for annot in annots) for annot in annots: start_idx = 50 if annot['description'] == 'BAD_peak' else 850 stop_idx = 149 if annot['description'] == 'BAD_peak' else 949 _check_annotation(raw_, annot, meas_date, first_samp, start_idx, stop_idx) annots, bads = annotate_amplitude(raw_, peak=5, flat=0., bad_percent=20.1) assert len(annots) == 2 assert len(bads) == 0 # check annotation instance assert all(annot['description'] in ('BAD_flat', 'BAD_peak') for annot in annots) for annot in annots: start_idx = 0 if annot['description'] == 'BAD_peak' else 800 stop_idx = 199 if annot['description'] == 'BAD_peak' else -1 _check_annotation(raw_, annot, meas_date, first_samp, start_idx, stop_idx) # test flat on already marked bad channel raw_ = raw.copy() raw_._data[-1, :] = 0. # this channel is already in info['bads'] annots, bads = annotate_amplitude(raw_, peak=None, flat=0., bad_percent=5) assert len(annots) == 0 assert len(bads) == 0 # test drift on already marked bad channel raw_ = raw.copy() raw_._data[-1, :] = np.arange(0, raw.times.size * 10, 10) annots, bads = annotate_amplitude(raw_, peak=5, flat=None, bad_percent=5) assert len(annots) == 0 assert len(bads) == 0