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']
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
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 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
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
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
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
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)
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
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]
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
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)
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)