Ejemplo n.º 1
0
def test_two_pd_alignment():
    """Test spliting photodiode events into two and adding."""
    out_dir = _TempDir()
    raw, _, events, _ = pd_parser.simulate_pd_data(prop_corrupted=0.)
    fname = op.join(out_dir, 'test-raw.fif')
    raw.save(fname)
    events2 = events[::2]
    events3 = events[1:][::2]
    # make behavior data
    np.random.seed(12)
    beh_events2 = events2[:, 0].astype(float) / raw.info['sfreq']
    offsets2 = np.random.random(len(beh_events2)) * 0.05 - 0.025
    beh_events2 += offsets2
    # make next one
    beh_events3 = events3[:, 0].astype(float) / raw.info['sfreq']
    offsets3 = np.random.random(len(beh_events3)) * 0.05 - 0.025
    beh_events3 += offsets3
    n_na = abs(len(beh_events2) - len(beh_events3))
    if len(beh_events2) > len(beh_events3):
        beh_events3 = list(beh_events3) + ['n/a'] * n_na
    elif len(beh_events3) > len(beh_events2):
        beh_events2 = list(beh_events2) + ['n/a'] * n_na
    beh = dict(trial=np.arange(len(beh_events2)),
               fix_onset_time=beh_events2,
               response_onset_time=beh_events3)
    behf = op.join(out_dir, 'behf-test.tsv')
    _to_tsv(behf, beh)
    pd_parser.parse_pd(fname,
                       pd_event_name='Fixation',
                       beh=beh,
                       pd_ch_names=['pd'],
                       beh_key='fix_onset_time',
                       zscore=20,
                       exclude_shift=0.05)
    pd_parser.parse_pd(fname,
                       pd_event_name='Response',
                       beh=beh,
                       pd_ch_names=['pd'],
                       beh_key='response_onset_time',
                       zscore=20,
                       add_events=True,
                       exclude_shift=0.05)
    raw = _read_raw(fname)
    annot, pd_ch_names, beh2 = _load_data(raw)
    raw.set_annotations(annot)
    events4, event_id = mne.events_from_annotations(raw)
    np.testing.assert_array_equal(events4[events4[:, 2] == 1, 0], events2[:,
                                                                          0])
    np.testing.assert_array_equal(events4[events4[:, 2] == 2, 0], events3[:,
                                                                          0])
    assert pd_ch_names == ['pd']
    np.testing.assert_array_equal(beh2['pd_parser_sample'], events2[:, 0])
Ejemplo n.º 2
0
def make_raw(out_dir):
    np.random.seed(99)
    raw, beh, events, corrupted = pd_parser.simulate_pd_data(seed=99)
    raw2 = mne.io.RawArray(
        np.random.random((3, raw._data.shape[1])),
        mne.create_info([f'ch{i}' for i in range(3)], raw.info['sfreq'],
                        ['eeg'] * 3))
    raw.add_channels([raw2])
    offsets = np.random.random(beh['time'].size) * 0.05 - 0.025
    beh['fix_onset_time'] = beh['time'] + offsets
    response_times = list(np.random.random(beh['time'].size))
    for i in np.random.choice(range(beh['time'].size), 3):
        response_times[i] = 'n/a'
    beh['fix_duration'] = [0.6] * beh['time'].size
    beh['go_time'] = np.random.random(beh['time'].size)
    beh['response_time'] = response_times
    fname = op.join(out_dir, 'test-raw.fif')
    raw.save(fname)
    behf = op.join(out_dir, 'behf-test.tsv')
    _to_tsv(behf, beh)
    return fname, behf, corrupted
Ejemplo n.º 3
0
def test_resync():
    """Test when event resynchronicazationu using ``resync`` is needed."""
    np.random.seed(12)
    raw, beh, events, corrupted_indices = \
        pd_parser.simulate_pd_data(prop_corrupted=0.)
    pd = raw._data[0]
    exclude_shift_i = np.round(raw.info['sfreq'] * exclude_shift).astype(int)
    candidates = _find_pd_candidates(pd,
                                     max_len=max_len,
                                     baseline=baseline,
                                     zscore=zscore,
                                     max_flip_i=max_flip_i,
                                     sfreq=raw.info['sfreq'])[0]
    beh_events = beh['time'] * raw.info['sfreq']
    offsets = (2 * resync * np.random.random(beh_events.size) -
               1) * raw.info['sfreq']
    beh_events += offsets
    beh_events -= beh_events[0]
    beh_events_adjusted, alignment, best_events = _find_best_alignment(
        beh_events, candidates, exclude_shift, resync, raw.info['sfreq'])
    errors = beh_events_adjusted - best_events + alignment
    resync_exclusions = np.where(abs(errors) > exclude_shift_i)[0]
    idx = resync_exclusions[0]
    correct = (best_events[idx], f'{idx}\nrecovered (not excluded)')
    assert len(resync_exclusions) > 0
    # test exclude ambiguous
    pd_events = _exclude_ambiguous_events(beh_events_adjusted, alignment,
                                          best_events, pd, candidates,
                                          exclude_shift, max_len,
                                          raw.info['sfreq'], recover, zscore)
    assert np.isnan(pd_events[resync_exclusions]).all()
    assert np.isnan(pd_events[np.isnan(best_events)]).all()
    with mock.patch('builtins.input', return_value='y'):
        found = _recover_event(idx, pd, beh_events_adjusted[idx] + alignment,
                               2 * resync, zscore, max_len, raw.info['sfreq'])
        assert abs(found[0] - correct[0]) < 2
        assert found[1] == correct[1]
import pd_parser
from pd_parser.parse_pd import _load_data

import matplotlib.pyplot as plt
import matplotlib.cm as cm

out_dir = _TempDir()

# simulate photodiode data
np.random.seed(29)
n_events = 300
# let's make our photodiode events on random uniform from 0.5 to 1 second
n_secs_on = np.random.random(n_events) * 0.5 + 0.5
prop_corrupted = 0.01
raw, beh, events, corrupted_indices = \
    pd_parser.simulate_pd_data(n_events=n_events, n_secs_on=n_secs_on,
                               prop_corrupted=prop_corrupted)

# make fake electrophysiology data
info = mne.create_info(['ch1', 'ch2', 'ch3'], raw.info['sfreq'], ['seeg'] * 3)
raw2 = mne.io.RawArray(np.random.random((3, raw.times.size)) * 1e-6, info)
raw2.info['lowpass'] = raw.info['lowpass']  # these must match to combine
raw.add_channels([raw2])
# bids needs these data fields
raw.info['dig'] = None
raw.info['line_freq'] = 60

# add some offsets to the behavior so it's a bit more realistic
offsets = np.random.randn(n_events) * 0.01
beh['time'] = np.array(beh['time']) + offsets

# save to disk as required by ``pd-parser``
Ejemplo n.º 5
0
import numpy as np

import mne
from mne.utils import _TempDir

import pd_parser
from pd_parser.parse_pd import _read_raw, _to_tsv

out_dir = _TempDir()
print(f'After running this example, you can find the data here: {out_dir}')

# simulate photodiode data
n_events = 300
prop_corrupted = 0.01
raw, beh, events, corrupted_indices = \
    pd_parser.simulate_pd_data(n_events=n_events,
                               prop_corrupted=prop_corrupted)

# make fake electrophysiology data
info = mne.create_info(['ch1', 'ch2', 'ch3'], raw.info['sfreq'],
                       ['seeg'] * 3)
raw2 = mne.io.RawArray(np.random.random((3, raw.times.size)) * 1e-6, info)
raw2.info['lowpass'] = raw.info['lowpass']  # these must match to combine
raw.add_channels([raw2])
# bids needs these data fields
raw.info['dig'] = None
raw.info['line_freq'] = 60

fname = op.join(out_dir, 'sub-1_task-mytask_raw.fif')
raw.save(fname)

# roundtrip so that raw is properly loaded from disk and has a filename
Ejemplo n.º 6
0
def test_inputs():
    """Test that inputs for functions raise necessary errors."""
    out_dir = _TempDir()
    # test tsv
    beh = dict(test=[1, 2], test2=[2, 1])
    _to_tsv(op.join(out_dir, 'test.tsv'), beh)
    assert beh == _read_tsv(op.join(out_dir, 'test.tsv'))
    with pytest.raises(ValueError, match='Unable to read'):
        _read_tsv('test.foo')
    with pytest.raises(ValueError, match='Error in reading tsv'):
        with open(op.join(out_dir, 'test.tsv'), 'w') as _:
            pass
        _read_tsv(op.join(out_dir, 'test.tsv'))
    with pytest.raises(ValueError, match='contains no data'):
        with open(op.join(out_dir, 'test.tsv'), 'w') as f:
            f.write('test')
        _read_tsv(op.join(out_dir, 'test.tsv'))
    with pytest.raises(ValueError, match='different lengths'):
        with open(op.join(out_dir, 'test.tsv'), 'w') as f:
            f.write('test\ttest2\n1\t1\n1')
        _read_tsv(op.join(out_dir, 'test.tsv'))
    with pytest.raises(ValueError, match='Empty data file, no keys'):
        _to_tsv(op.join(out_dir, 'test.tsv'), dict())
    with pytest.raises(ValueError, match='Unable to write'):
        _to_tsv('foo.bar', dict(test=1))
    # test read
    raw, beh, events, corrupted_indices = pd_parser.simulate_pd_data()
    with pytest.raises(ValueError, match='must be loaded from disk'):
        _read_raw(raw, preload=True)
    raw.save(op.join(out_dir, 'test-raw.fif'), overwrite=True)
    with pytest.raises(ValueError, match='not recognized'):
        _read_raw('foo.bar')
    raw2 = _read_raw(op.join(out_dir, 'test-raw.fif'), preload=True)
    np.testing.assert_array_almost_equal(raw._data, raw2._data, decimal=3)
    # test load beh
    with pytest.raises(ValueError, match='not in the columns'):
        _load_beh(op.join(basepath, 'pd_events.tsv'), 'foo')
    # test get pd data
    with pytest.raises(ValueError, match='in raw channel names'):
        _get_data(raw, ['foo'])
    with pytest.raises(ValueError, match='in raw channel names'):
        _get_channel_data(raw, ['foo'])
    with pytest.raises(ValueError, match='baseline must be between 0 and 1'):
        pd_parser.parse_pd(raw, beh=beh, baseline=2)
    with pytest.raises(FileNotFoundError, match='fname does not exist'):
        _load_data('bar/foo.fif')
    with pytest.raises(ValueError, match='pd-parser data not found'):
        raw.save(op.join(out_dir, 'foo.fif'))
        _load_data(op.join(out_dir, 'foo.fif'))
    # test i/o
    raw3 = _read_raw(op.join(out_dir, 'test-raw.fif'))
    _save_data(raw3,
               events=np.arange(10),
               event_id='Fixation',
               ch_names=['pd'],
               beh=beh,
               add_events=False)
    with pytest.raises(ValueError, match='`pd_parser_sample` is not allowed'):
        _save_data(raw3,
                   events=events,
                   event_id='Fixation',
                   ch_names=['pd'],
                   beh=beh,
                   add_events=False)
    annot, pd_ch_names, beh2 = _load_data(raw3)
    raw.set_annotations(annot)
    events2, event_id = mne.events_from_annotations(raw)
    np.testing.assert_array_equal(events2[:, 0], np.arange(10))
    assert event_id == {'Fixation': 1}
    assert pd_ch_names == ['pd']
    np.testing.assert_array_equal(beh2['time'], beh['time'])
    np.testing.assert_array_equal(beh2['pd_parser_sample'], np.arange(10))
    # check overwrite
    behf = op.join(out_dir, 'behf-test.tsv')
    _to_tsv(behf, beh)
    with pytest.raises(ValueError, match='directory already exists'):
        pd_parser.parse_pd(raw3, beh=behf)
    pd_parser.parse_pd(raw3, beh=None, pd_ch_names=['pd'], overwrite=True)
    annot, pd_ch_names, beh = _load_data(raw3)
    raw3.set_annotations(annot)
    events2, _ = mne.events_from_annotations(raw3)
    assert all([event in events2[:, 0] for event in events[:, 0]])
    assert pd_ch_names == ['pd']
    assert beh is None
    # test overwrite
    raw = _read_raw(op.join(out_dir, 'test-raw.fif'))
    with pytest.raises(ValueError, match='data directory already exists'):
        _check_overwrite(raw, add_events=False, overwrite=False)
Ejemplo n.º 7
0
def test_core():
    """Test the core functions of aligning photodiode events."""
    np.random.seed(121)
    raw, beh, events, corrupted_indices = pd_parser.simulate_pd_data(seed=1211)
    pd = raw._data[0]
    # test find pd candidates
    max_len = 1.5
    exclude_shift_i = np.round(raw.info['sfreq'] * exclude_shift).astype(int)
    max_len_i = np.round(raw.info['sfreq'] * max_len).astype(int)
    baseline_i = np.round(max_len_i * baseline / 2).astype(int)
    resync_i = np.round(raw.info['sfreq'] * resync).astype(int)
    pd_diff = np.diff(pd)
    pd_diff -= np.median(pd_diff)
    median_std = np.median([
        np.std(pd_diff[i - baseline_i:i])
        for i in range(baseline_i,
                       len(pd_diff) - baseline_i, baseline_i)
    ])
    assert _check_if_pd_event(pd_diff, events[0, 0] - 1, max_len_i, zscore,
                              max_flip_i, median_std) == \
        ('up', events[0, 0], events[0, 0] + raw.info['sfreq'])  # one sec event
    assert _check_if_pd_event(pd, baseline_i,
                              max_len_i, zscore, max_flip_i, median_std) == \
        (None, None, None)
    candidates = _find_pd_candidates(pd,
                                     max_len=max_len,
                                     baseline=baseline,
                                     zscore=zscore,
                                     max_flip_i=max_flip_i,
                                     sfreq=raw.info['sfreq'])[0]
    candidates_set = set(candidates)
    assert all([event in candidates for event in events[:, 0]])
    # test pd event dist
    assert np.isnan(
        _event_dist(len(raw) + 10, candidates_set, len(raw),
                    exclude_shift_i)).all()
    assert _event_dist(events[2, 0] + 10, candidates_set, len(raw),
                       exclude_shift_i) == (10, events[2, 0])
    assert _event_dist(events[2, 0] - 10, candidates_set, len(raw),
                       exclude_shift_i) == (-10, events[2, 0])
    # test find best alignment
    beh_events = beh['time'][2:] * raw.info['sfreq']
    offsets = (np.random.random(beh_events.size) * exclude_shift /
               2) * raw.info['sfreq']
    beh_events += offsets
    beh_events -= beh_events[0]  # throw off the alignment, make it harder
    beh_events_adjusted, best_events = _check_alignment(
        beh_events, candidates[2], candidates, candidates_set, resync_i)
    errors = beh_events_adjusted - best_events + candidates[2]
    assert all([
        np.isnan(e) if i + 2 in corrupted_indices else e < exclude_shift_i
        for i, e in enumerate(errors)
    ])
    beh_events_adjusted, alignment, best_events = _find_best_alignment(
        beh_events, candidates, exclude_shift, resync, raw.info['sfreq'])
    assert abs(alignment - candidates[2]) < exclude_shift_i
    errors = beh_events_adjusted - best_events + alignment
    assert all([
        np.isnan(e) or abs(e) > exclude_shift_i if i +
        2 in corrupted_indices else abs(e) < exclude_shift_i
        for i, e in enumerate(errors)
    ])
    # test exclude ambiguous
    pd_events = _exclude_ambiguous_events(beh_events, alignment, best_events,
                                          pd, candidates, exclude_shift,
                                          max_len, raw.info['sfreq'], recover,
                                          zscore)
    assert all([i - 2 not in pd_events for i in corrupted_indices])
    np.testing.assert_array_equal(pd_events[~np.isnan(pd_events)], events[2:,
                                                                          0])