def make_deterministic_exp():
    Experiment.basic(('participant', 'block', 'trial'),
                     {'block': {'b': [0, 1, 2]}, 'trial': {'a': [False, True]}},
                     ordering_by_level={'trial': Ordering(4),
                                        'block': Ordering(4),
                                        'participant': Ordering()},
                     filename='test.pkl').save()
def participant_context(exp: Experiment, participant: ExperimentSection):
    term = Terminal()
    exp.session_data['term'] = term
    exp.session_data['stimuli'] = [
        jpg_to_ascii(os.path.join('stimuli', '{:02}.jpg'.format(i)), background='light', height=term.height - 2)
        for i in range(1, 16)
    ]

    with term.fullscreen():
        print(term.move(int(term.width//2), int(term.height//2)))
        response_type = participant.data['response_type']
        instructions = exp.experiment_data['instructions']
        for i, instruction in enumerate(instructions, 1):
            message = get_message(instruction, response_type)

            if message.startswith('_example'):
                show_example(term, response_type, message.split('_')[2], exp.session_data['stimuli'],
                             exp.experiment_data['example_response_message'],
                             ascii_stimuli=exp.experiment_data.get('ascii_stimuli', True),
                             stimulus_time=8)

            else:
                reset(term)
                wrapped_multiline_print_at_location(term, message, X_MARGIN, Y_MARGIN, int(term.width//2))
                with term.location(term.width//2, term.height - 3):
                    print('{}/{}'.format(i, len(instructions)))
                time.sleep(1)  # Ensure we don't accidentally skip a message.
                input()
        yield
        reset(term)
        print(exp.experiment_data['exit_message'])
        input()

    del exp.session_data['term']
예제 #3
0
def make_manual_exp():
    tree = DesignTree([('participant', [Design(ordering=Shuffle(2))]),
                       ('block', [Design(ivs={'b': [0, 1, 2]}, ordering=CompleteCounterbalance())]),
                       ('trial', [Design({'a': [False, True]}, ordering=Shuffle(4))]),
                       ])
    exp = Experiment(tree)
    exp.set_run_callback(trial)
    return exp
def make_deterministic_exp():
    Experiment.basic(('participant', 'block', 'trial'), {
        'block': {
            'b': [0, 1, 2]
        },
        'trial': {
            'a': [False, True]
        }
    },
                     ordering_by_level={
                         'trial': Ordering(4),
                         'block': Ordering(4),
                         'participant': Ordering()
                     },
                     filename='test.yaml').save()
def main():
    exp = Experiment.from_yaml_file(sys.argv[1])
    exp.set_run_callback(run_trial)
    exp.set_context_manager('participant', participant_context)
    exp.set_context_manager('block', block_context)
    exp.save()
    return 0
예제 #6
0
def main(args=None):
    # The console script created by setuptools takes the cwd off the path.
    sys.path.insert(0, os.getcwd())

    scheme = Schema({'--debug': bool,
                     '--delim': str,
                     '--demo': bool,
                     '--help': bool,
                     '--float': Or(None, str),
                     '--from': Or(None, Use(lambda x: list(map(int, x.split(','))))),
                     '--nan': Or(None, str),
                     '--next': Or(None, str),
                     '--no-index-label': bool,
                     '--not-finished': bool,
                     '-o': Or(None, str),
                     '--skip': Or(None, Use(lambda x: x.split(','))),
                     '--skip-parents': bool,
                     '--version': bool,
                     '<data-file>': Or(None, str),
                     '<exp-file>': Or(lambda x: x is None, os.path.exists, error='Invalid <exp-file>'),
                     '<level>': [str],
                     '<n>': [And(Use(int), lambda n: n > 0)],
                     'export': bool,
                     'resume': bool,
                     'run': bool,
                     })

    options = scheme.validate(docopt(__doc__, argv=args, version=__version__))

    if options['--debug']:
        logging.basicConfig(level=logging.DEBUG)

    if options['run'] or options['resume']:
        exp = Experiment.load(options['<exp-file>'])
        kwargs = {'demo': options['--demo'],
                  'parent_callbacks': not options['--skip-parents'],
                  'resume': options['resume'],
                  'session_options': options['-o'],
                  'from_section': options['--from'],
                  }

        if options['--next']:
            kwargs.update(section_obj=exp.find_first_not_run(
                options['--next'], by_started=not options['--not-finished']))

        elif options['resume'] and not options['<n>']:
            kwargs.update(section_obj=exp.find_first_partially_run(options['<level>'][0]))

        else:
            kwargs.update(zip(options['<level>'], options['<n>']))

        run_experiment_section(exp, **kwargs)

    elif options['export']:
        export_experiment_data(options['<exp-file>'], options['<data-file>'],
                               float_format=options['--float'],
                               skip_columns=options['--skip'],
                               index_label=False if options['--no-index-label'] else None,
                               na_rep=options['--nan'],
                               sep=options['--delim'])
예제 #7
0
def load_data(filename, stack=True, collapse_unsuccesful=True, drop_outbound=None, drop_return=None):
    if drop_outbound is None:
        drop_outbound = []
    if drop_return is None:
        drop_return = []

    df = Experiment.load(filename).dataframe.dropna()
    for column, type_ in [
        ('height', 'int'),
        ('hip_height', 'float'),
        ('knee_height', 'float'),
        ('lowest_height_not_afforded', 'int'),
    ]:
        df[column] = df[column].astype(type_)

    df.loc[df.index.get_level_values('participant').isin(drop_outbound), 'outbound'] = None
    df.loc[df.index.get_level_values('participant').isin(drop_return), 'return'] = None

    df['relative_height'] = df['height'] - df['lowest_height_not_afforded']
    df['scaled_height'] = df['height'] / df['lowest_height_not_afforded']

    if collapse_unsuccesful:
        for phase in _phases:
            df.loc[df[phase] == 'unsuccessful', phase] = 'over'

    if stack:
        df = pd.concat((df, df), keys=_phases, names=['phase'])
        df = df.reset_index().set_index(['participant', 'trial', 'phase']).sort()
        df['action'] = [row[phase] for (p, t, phase), row in df.iterrows()]
        for phase in _phases:
            del df[phase]
        df = df.dropna()

    return df
예제 #8
0
def make_manual_exp():
    tree = DesignTree.new([('participant', [Design(ordering=Shuffle(2))]),
                           ('block', [Design(ivs={'b': [0, 1, 2]}, ordering=CompleteCounterbalance())]),
                           ('trial', [Design({'a': [False, True]}, ordering=Shuffle(4))]),
                           ])
    exp = Experiment.new(tree)
    exp.add_callback('trial', trial)
    return exp
def main():
    experiment = Experiment.from_yaml_file(sys.argv[1])
    experiment.set_context_manager('participant', setup_participant)
    if 'block' in experiment.levels:
        experiment.set_context_manager('block', setup_block)
    experiment.set_run_callback(run_trial)
    experiment.save()
    return 0
예제 #10
0
def make_standard_exp():
    exp = Experiment.basic(('participant', 'block', 'trial'),
                           {'block': [('b', [0, 1, 2])],
                            'trial': [('a', [False, True])]},
                           ordering_by_level={'trial': Shuffle(4),
                                              'block': CompleteCounterbalance(),
                                              'participant': Shuffle(2)})
    exp.add_callback('trial', trial)
    return exp
예제 #11
0
def test_doc_yaml():
    experiment = Experiment.from_yaml_file('tests/doctest.yml')
    assert len(experiment) == 40
    participant = experiment[1]
    assert len(participant) == 2
    first_session, second_session = participant
    assert len(first_session[1]) == len(second_session[1]) == 4
    first_experimental_section = first_session[2]
    second_experimental_section = second_session[2]
    assert len(first_experimental_section) == 60
    assert first_experimental_section[1].level == 'trial'
    assert first_experimental_section[1].is_bottom_level
    assert len(second_experimental_section) == 2
    assert second_experimental_section[1].level == 'block'
    assert len(second_experimental_section[1]) == len(second_experimental_section[2]) == 30
def test_exception():
    exp = make_blocked_exp()
    exp.set_run_callback(bad_trial)
    exp.save()
    exp.save('test.pkl')
    with pytest.raises(QuitSession):
        run_experiment_section('test.pkl', participant=1)

    exp = Experiment.load('test.pkl')
    assert exp.subsection(participant=1, block=1, trial=1).has_started
    assert not exp.subsection(participant=1, block=1, trial=1).has_finished
    os.remove('test.pkl')

    e = QuitSession('message')
    assert e.__str__() == 'message'
    with pytest.raises(QuitSession):
        raise e
def test_exception():
    exp = make_blocked_exp()
    exp.add_callback('trial', bad_trial)
    exp.save()
    exp.save('test.yaml')
    with pytest.raises(QuitSession):
        run_experiment_section('test.yaml', participant=1)

    exp = Experiment.load('test.yaml')
    assert exp.subsection(participant=1, block=1, trial=1).has_started
    assert not exp.subsection(participant=1, block=1, trial=1).has_finished
    os.remove('test.yaml')

    e = QuitSession('message')
    assert e.__str__() == 'message'
    with pytest.raises(QuitSession):
        raise e
예제 #14
0
def test_experiment_from_yaml_file():
    experiment = Experiment.from_yaml_file('tests/test.yml')
    yield check_equality, experiment.filename, 'test.dat'
    yield check_equality, experiment.experiment_data, {'data': [1, 2, 3, 4, 5]}
    yield check_equality, len(experiment), 2*2*3
    participant = experiment.subsection(participant=1)
    yield check_equality, participant.level, 'participant'
    yield check_equality, len(participant), 3
    yield check_equality, participant[1].data['design'], 'practice'
    yield check_equality, participant[2].data['design'], participant[3].data['design'], 'test'
    practice_session = participant[1]
    test_session = participant[2]
    yield check_equality, practice_session.level, test_session.level, 'session'
    yield check_equality, len(practice_session), 1
    yield check_equality, len(test_session), 2
    test_block = test_session[1]
    yield check_equality, len(test_block), 2*2 + 2*3
    yield check_in, (trial.data['difficulty'] for trial in test_block[:4]), [1, 3]
    yield check_in, (trial.data['difficulty'] for trial in test_block[5:]), [5, 7]
def test_exp_repr():
    make_deterministic_exp()
    e = Experiment.load('test.pkl')
    assert e == eval(repr(e))
    for file in glob('test.pkl*'):
        os.remove(file)
예제 #16
0
def test_demo_parent_has_started():
    experiment = Experiment.from_yaml_file('tests/test.yml')
    experiment.run_section(experiment[1][2], demo=True)
    assert not experiment.has_started
예제 #17
0
def test_experiment_from_spec():
    spec = {
        'design':
        {
            'main':
            [
                {
                    'name': 'participant',
                    'ivs': {'a': [1, 2], 'b': [1, 2]},
                    'number': 3,
                    'ordering': 'Shuffle',
                },
                {
                    'name': 'session',
                    'ivs': {'design': ['practice', 'test']},
                    'design_matrix': [[0], [1], [1]],
                },
            ],
            'practice':
            [
                {
                    'name': 'block'
                },
                {
                    'name': 'trial',
                    'ivs': {'difficulty': [1, 2]},
                    'n': 2,
                    'order': 'Shuffle',
                },
            ],
            'test':
            [
                {
                    'name': 'block',
                    'n': 2,
                },
                [
                    {
                        'name': 'trial',
                        'ivs': {'difficulty': [1, 3]},
                        'number': 2,
                        'order': 'Shuffle',
                    },
                    {
                        'ivs': {'difficulty': [5, 7]},
                        'n': 3,
                        'order': 'Shuffle',
                    },
                ],
            ],
        },
        'data': [1, 2, 3, 4, 5],
        'file': 'test.dat',
    }
    experiment = Experiment.from_dict(spec)
    yield check_equality, experiment.filename, 'test.dat'
    yield check_equality, experiment.experiment_data, {'data': [1, 2, 3, 4, 5]}
    yield check_equality, len(experiment), 2*2*3
    participant = experiment.subsection(participant=1)
    yield check_equality, participant.level, 'participant'
    yield check_equality, len(participant), 3
    yield check_equality, participant[1].data['design'], 'practice'
    yield check_equality, participant[2].data['design'], participant[3].data['design'], 'test'
    practice_session = participant[1]
    test_session = participant[2]
    yield check_equality, practice_session.level, test_session.level, 'session'
    yield check_equality, len(practice_session), 1
    yield check_equality, len(test_session), 2
    test_block = test_session[1]
    yield check_equality, len(test_block), 2*2 + 2*3
    yield check_in, (trial.data['difficulty'] for trial in test_block[:4]), [1, 3]
    yield check_in, (trial.data['difficulty'] for trial in test_block[5:]), [5, 7]
예제 #18
0
def make_blocked_exp():
    exp = Experiment.blocked({'a': [False, True]}, 2,
                             block_ivs={'b': [0, 1, 2]},
                             orderings={'trial': Shuffle(4), 'block': CompleteCounterbalance()})
    exp.add_callback('trial', trial)
    return exp
예제 #19
0
def make_simple_exp():
    ivs = {'a': [False, True], 'b': [0, 1, 2]}
    exp = Experiment.within_subjects(ivs, 10, ordering=Shuffle(4))
    exp.add_callback('trial', trial)
    return exp
def test_cli():
    exp = make_blocked_exp()
    exp.set_context_manager('participant', participant_context)
    exp.set_context_manager('block', block_context)
    exp.filename = 'test.pkl'
    exp.save()

    call_cli('exp run test.pkl --next participant')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] == 1:
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp --demo run test.pkl participant 2 block 1')
    for row in exp.dataframe.iterrows():
        if row[0][0] == 1:
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.pkl participant 2 block 1')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] == 1 or (row[0][0] == 2 and row[0][1] == 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp resume test.pkl participant')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2:
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.pkl --next trial')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0] == (3, 1, 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp resume test.pkl participant 3 block 1 --demo')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0] == (3, 1, 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp --debug resume test.pkl participant 3 block 1')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0][:2] == (3, 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.pkl participant 3 block 3 --from 3')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0][:2] == (3, 1) or (row[0][:2] == (3, 3) and row[0][-1] >= 3):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.pkl participant 3 --from 2,4')
    exp = Experiment.load('test.pkl')
    for row in exp.dataframe.iterrows():
        if (row[0][0] <= 2
                or row[0][:2] == (3, 1)
                or (row[0][:2] == (3, 2) and row[0][-1] >= 4)
                or (row[0][:2] == (3, 3) and row[0][2] > 2)):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    for file in glob('test.pkl*'):
        os.remove(file)
예제 #21
0
def main(args=None):
    # The console script created by setuptools takes the cwd off the path.
    sys.path.insert(0, os.getcwd())

    scheme = Schema({
        '--debug':
        bool,
        '--delim':
        str,
        '--demo':
        bool,
        '--help':
        bool,
        '--float':
        Or(None, str),
        '--from':
        Or(None, Use(lambda x: list(map(int, x.split(','))))),
        '--nan':
        Or(None, str),
        '--next':
        Or(None, str),
        '--no-index-label':
        bool,
        '--not-finished':
        bool,
        '-o':
        Or(None, str),
        '--skip':
        Or(None, Use(lambda x: x.split(','))),
        '--skip-parents':
        bool,
        '--version':
        bool,
        '<data-file>':
        Or(None, str),
        '<exp-file>':
        Or(lambda x: x is None, os.path.exists, error='Invalid <exp-file>'),
        '<level>': [str],
        '<n>': [And(Use(int), lambda n: n > 0)],
        'export':
        bool,
        'resume':
        bool,
        'run':
        bool,
    })

    options = scheme.validate(docopt(__doc__, argv=args, version=__version__))

    if options['--debug']:
        logging.basicConfig(level=logging.DEBUG)

    if options['run'] or options['resume']:
        exp = Experiment.load(options['<exp-file>'])
        kwargs = {
            'demo': options['--demo'],
            'parent_callbacks': not options['--skip-parents'],
            'resume': options['resume'],
            'session_options': options['-o'],
            'from_section': options['--from'],
        }

        if options['--next']:
            kwargs.update(section_obj=exp.find_first_not_run(
                options['--next'], by_started=not options['--not-finished']))

        elif options['resume'] and not options['<n>']:
            kwargs.update(section_obj=exp.find_first_partially_run(
                options['<level>'][0]))

        else:
            kwargs.update(zip(options['<level>'], options['<n>']))

        run_experiment_section(exp, **kwargs)

    elif options['export']:
        export_experiment_data(
            options['<exp-file>'],
            options['<data-file>'],
            float_format=options['--float'],
            skip_columns=options['--skip'],
            index_label=False if options['--no-index-label'] else None,
            na_rep=options['--nan'],
            sep=options['--delim'])
def test_cli():
    exp = make_blocked_exp()
    exp.add_callback('participant', participant_context, is_context=True)
    exp.add_callback('block', block_context, is_context=True)
    exp.filename = 'test.yaml'
    exp.save()

    call_cli('exp run test.yaml --next participant')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] == 1:
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp --demo run test.yaml participant 2 block 1')
    for row in exp.dataframe.iterrows():
        if row[0][0] == 1:
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.yaml participant 2 block 1')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] == 1 or (row[0][0] == 2 and row[0][1] == 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp resume test.yaml participant')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2:
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.yaml --next trial')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0] == (3, 1, 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp resume test.yaml participant 3 block 1 --demo')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0] == (3, 1, 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp --debug resume test.yaml participant 3 block 1')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0][:2] == (3, 1):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.yaml participant 3 block 3 --from 3')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if row[0][0] <= 2 or row[0][:2] == (3, 1) or (row[0][:2] == (3, 3)
                                                      and row[0][-1] >= 3):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    call_cli('exp run test.yaml participant 3 --from 2,4')
    exp = Experiment.load('test.yaml')
    for row in exp.dataframe.iterrows():
        if (row[0][0] <= 2 or row[0][:2] == (3, 1)
                or (row[0][:2] == (3, 2) and row[0][-1] >= 4)
                or (row[0][:2] == (3, 3) and row[0][2] > 2)):
            yield check_trial, row
        else:
            assert isnan(row[1]['result'])

    for file in glob('test.yaml*'):
        os.remove(file)