#short version from expyriment import design, control, stimuli, misc, io from pathlib import Path import random #global settings control.set_develop_mode() exp = design.Experiment(name='Inversion Effect') control.initialize(exp) ####################################### DESIGN ######################################################### # Defines experiment hierarchy # each category_block (faces_chairs, bodies_chairs) consits of 256 trials = total of 512 trials for category_block_order in ['faces_chairs', 'bodies_chairs']: # each category_block is split up into 8 small experiments consiting of 32 trials each # --> each small experiment is represented by a block object (16 blocks in total - 8 faces_chairs + 8 bodies_chairs) for small_exp in range(8): block = design.Block() block.set_factor("category_order", category_block_order) #prepare variables needed based on between_subject variable if category_block_order == 'faces_chairs': categories = ['faces', 'chairs'] else: categories = ['bodies', 'chairs'] #prepare main path to get the stimuli path = Path.cwd() / category_block_order #each small experiment consists of 4x 8 unique conditions = 32 trials in total #Condition Design - 2x2x2 design: CATEGORY x ORIENTATION x DIRECTION --> 8 unique conditions for category in categories: for orientation in ['upright', 'inverted']: for direction in ['facing', 'non_facing']: trial = design.Trial() #get random path to one image within the stimulus_type stim_paths = path / category / orientation / direction if category == 'faces': stimulus = random.choice(list(stim_paths.rglob("*.tif"))) else: stimulus = random.choice(list(stim_paths.rglob("*.jpg"))) #get path to one mask mask_paths = path / 'masks' mask = random.choice(list(mask_paths.rglob("*.jpg"))) #add stimulus and mask to trial trial.set_factor('target_stimulus', str(stimulus)) trial.set_factor('orientation', orientation) trial.set_factor('direction', direction) trial.set_factor('mask', str(mask)) #add the trial to the small experiment block block.add_trial(trial, copies=4) #shuffle the small experiment block and add the small experiment as a block to the experiment block.shuffle_trials() exp.add_block(block) #prepare data output - order is important exp.data_variable_names = ["category mapping", "block", "stim orient", "stim dir", "rt", "accuracy"] # set experimental constants - T_FIXCROSS = [500, 750, 1000] T_BLANK = 200 T_MASK = 250 T_TARGET = 30 #TODO PREPARE THE POSITON OF THE SIMULI # prepare and preload components needed within each trial blankscreen = stimuli.BlankScreen() #TODO: color preference blankscreen.preload() fixcross = stimuli.FixCross() #TODO - check position and color fixcross.preload() ################### START ################### # present a subject number screen and is ready after initialization control.start(exp) # Run the actual experiment - loop over all blocks and trials for block in exp.blocks: #TODO: instructions + position # INSTRUCTIONS - shown between each block if block.get_factor('category_order') == 'faces_chairs': instruction = 'Press for facing and for non-facing.' else: instruction = 'Press for non_facing and for facing.' stimuli.TextScreen('Indicate the orientation of the images: ', instruction + '\n\nPress space to start the experiment').present() exp.keyboard.wait(misc.constants.K_SPACE) for trial in block.trails: T_FIX = design.randomize.rand_element(T_FIXCROSS) # present fixation cross & prepare trial in the mean time fixcross.present() exp.clock.reset_stopwatch() target = stimuli.Picture(trial.get_factor("target_stimulus")) #TODO: define position target.preload() mask = stimuli.Picture(trial.get_factor("mask")) #TODO: define position mask.preload() exp.clock.wait(T_FIX - exp.clock.stopwatch_time) # present blankscreen for fixed interval blankscreen.present() exp.clock.wait(T_BLANK) # present target stimulus target.present() exp.clock.wait(T_TARGET) # present mask mask.present() exp.clock.wait(T_MASK) # present blankscreen and record button press blankscreen.present() #presented as long as keyboard(?) button, rt = exp.keyboard.wait(keys=[misc.constants.K_d, misc.constants.K_k]) #TODO: could specify a max waiting time with (duration=...) #continue to present blankscreen while logging data blankscreen.present() exp.clock.reset_stopwatch() #calculate accuracy dir = trial.get_factor('direction') if block.get_factor('category_order') == 'faces_chairs': if (button == d) and (dir == 'facing'): accuracy = 1 else: accuracy = 0 else: if (button == k) and (dir == 'facing'): accuracy = 1 else: accuracy = 0 #LOGGING DATA: order must correspond to the order predefined for the category names - ["category mapping", "block", "stim orient", "stim dir", "rt", "accuracy"] exp.data.add([block.get_factor('category_order'), block.id, trial.get_factor('orientation'), trial.get_factor('direction'), rt, accuracy]) exp.data.save() target.unload() mask.unload() exp.clock.wait(T_BLANK - exp.clock.stopwatch_time) ################### END EXPERIMENT ################### #shows an ending experiment screen and saves data control.end(goodbye_text = "Thank you very much for participating in our experiment", goodbye_delay = 5000)