def DynamicDotBox(self, duration=None, update_interval=jitter(1 / 20., (1 / 10.) - (1 / 20.)), **dotbox_args): """Display random dots that update at an interval. Parameters ---------- duration : float or None Duration to show the random dots. update_interval : float How often to update the random dots. Default is to jitter between 10 and 20 Hz. dotbox_args : kwargs See the DotBox for any kwargs options to control the DotBox Note: You can access the dotbox via the `db` attribute of the subroutine. Examples -------- Display a dynamic dot box with 40 dots for 3 seconds: :: DynamicDotBox(size=(500, 500), num_dots=40, duration=3.0) Display two dynamic dot boxes side-by-side until a key press: :: with Parallel(): ddb1 = DynamicDotBox(center_x=exp.screen.center_x-200, num_dots=40, size=(400, 400)) ddb2 = DynamicDotBox(center_x=exp.screen.center_x+200, num_dots=80, size=(400, 400)) with UntilDone(): kp = KeyPress() Log(appear_time=ddb1.db.appear_time) """ # show the dotbox with Parallel(): db = DotBox(duration=duration, **dotbox_args) self.db = db with Meanwhile(): # redraw the dots self.start_dots = db.num_dots with Loop() as l: Wait(duration=update_interval) # hack to make 1.8 work with If((l.i % 2) == 0): self.ndots = self.start_dots + .01 with Else(): self.ndots = self.start_dots #db.update(save_log=False, **dotbox_args) db.update(save_log=False, num_dots=self.ndots)
def JitteredPulses(self, code=1, width=0.010, port=0, pause_between=3.0, jitter_between=3.0, sync_style="parallel"): """Send pulses separated by a jittered wait. The typical use case for this subroutine is to send a random train of pulses during an EEG experiment to allow for subsequent synchronization of the EEG data with the behavioral data. This would be accomplished by calling JitteredPulses within a Meanwhile as the next state following the instantiation of the Experiment: exp = Experiment() with Meanwhile(): JitteredPulses() """ # loop indefinitely with Loop(): # send a pulse pulse = Pulse(code=code, port=port, width=width, sync_style=sync_style) Done(pulse) # do a jittered wait Wait(duration=pause_between, jitter=jitter_between) # Log the pulse to a pulse-specific log Log(name='pulse', pulse_on=pulse.pulse_on, pulse_code=pulse.code, pulse_off=pulse.pulse_off, pulse_port=pulse.port, pulse_width=pulse.width)
if __name__ == '__main__': from experiment import Experiment, Get, Set, Log from state import Wait, Func, Loop def print_dt(state, *args): print args, state.dt exp = Experiment() Func(print_dt, args=['Mouse Press Test']) Set('last_pressed','') with Loop(conditional=(Get('last_pressed')!='RIGHT')): kp = MousePress(buttons=['LEFT','RIGHT'], correct_resp='RIGHT') Func(print_dt, args=[kp['pressed'],kp['rt'],kp['correct']]) Set('last_pressed',kp['pressed']) Log(pressed=kp['pressed'], rt=kp['rt']) kp = MousePress(buttons=['LEFT','RIGHT'], correct_resp='RIGHT') Func(print_dt, args=[kp['pressed'],kp['rt'],kp['correct']]) Wait(1.0) kp = MousePress() Func(print_dt, args=[kp['pressed'],kp['rt'],kp['correct']]) Wait(1.0) kp = MousePress(duration=2.0) Func(print_dt, args=[kp['pressed'],kp['rt'],kp['correct']])
OUTLET = init_lsl_outlet(server_name='MarkerStream', server_type='Markers', nchans=1, suggested_freq=500, channel_format='int32', unique_id='SMILE_LSL_OUT') # Signal the beginning of the experiment. LSLPush(server=OUTLET, val=55) # Wait for the experiment to start! Wait(2.) with Parallel(): Label(text="We will now push 10 markers.", blocking=False) with Loop(10, blocking=False): # Create the push state push_out = LSLPush(server=OUTLET, val=111) # Log like this if you want. #Log(name="MAKERS", # push_time=push_out.push_time) Wait(1.) exp.run()
if __name__ == '__main__': from experiment import Experiment from state import Wait, Debug, Loop, UntilDone, Log, Meanwhile exp = Experiment() with Meanwhile(): KeyRecord(name="record_all_key_presses") Debug(name='Press T+G+D or SHIFT+Q+R') Wait(until=((Key("T") & Key("G") & Key("D")) | (Key("SHIFT") & Key("Q") & Key("R")))) Debug(name='Key Press Test') exp.last_pressed = '' with Loop(conditional=(exp.last_pressed != 'K')): kp = KeyPress(keys=['J', 'K'], correct_resp='K') Debug(pressed=kp.pressed, rt=kp.rt, correct=kp.correct) exp.last_pressed = kp.pressed Log(pressed=kp.pressed, rt=kp.rt) KeyRecord() with UntilDone(): kp = KeyPress(keys=['J', 'K'], correct_resp='K') Debug(pressed=kp.pressed, rt=kp.rt, correct=kp.correct) Wait(1.0) kp = KeyPress() Debug(pressed=kp.pressed, rt=kp.rt, correct=kp.correct) Wait(1.0)
pulse_code=pulse.code, pulse_off=pulse.pulse_off, pulse_port=pulse.port, pulse_width=pulse.width) if __name__ == '__main__': from experiment import Experiment from state import Meanwhile, Debug # set up default experiment exp = Experiment() # test running pulses whilst the rest of the experiment is going with Meanwhile(): with Loop(): pulse = Pulse(code='S1') Wait(duration=1.0, jitter=1.0) Log(name='pulse', pulse_on=pulse.pulse_on, pulse_code=pulse.code, pulse_off=pulse.pulse_off) # First wait for a bit and send some pulses Wait(10) # print something Debug(width=exp.screen.width, height=exp.screen.height) # run the exp exp.run(trace=False)
from keyboard import KeyPress exp = Experiment(background_color=("purple", .3)) Wait(.5) g = MovingDots(radius=300, scale=10, num_dots=4, motion_props=[{"coherence": 0.25, "direction": 0, "direction_variance": 0}, {"coherence": 0.25, "direction": 90, "direction_variance": 0}, {"coherence": 0.25, "direction": 180, "direction_variance": 0}, {"coherence": 0.25, "direction": 270, "direction_variance": 0}]) with UntilDone(): KeyPress() with Meanwhile(): g.slide(color='red', duration=4.0) Wait(.25) with Loop(4): MovingDots() with UntilDone(): KeyPress() Debug(rate=g.widget.refresh_rate) exp.run(trace=False)
# Show(Image('face-smile.png', x=exp.window.width//2, y=exp.window.height//2), # duration=2.0) # Wait(1.0) def print_dt(state, *txt): for t in txt: print t print now()-state.state_time, state.dt print block = [{'text':['a','b','c']}, {'text':['d','e','f']}, {'text':['g','h','i']}] with Loop(block) as trial: Set('stim_times',[]) with Loop(trial.current['text']) as item: ss = Show(Text(item.current, color=(255,0,0,255)), duration=1.0) #Wait(1.0) #Unshow(ss) Wait(.5) #Set('stim_times',Get('stim_times')+[ss['last_flip']]) #Set('stim_times',Get('stim_times')+[ss['show_time']]) Set('stim_times',Get('stim_times').append(ss.show_time)) #Set('stim_times', # Get('stim_times')+Ref(gfunc=lambda : list(ss.show_time))) Func(print_dt, args=[ss.show_time,Get('stim_times')])
}, { "coherence": 0.25, "direction": 180, "direction_variance": 0 }, { "coherence": 0.25, "direction": 270, "direction_variance": 0 }]) with UntilDone(): KeyPress() with Meanwhile(): g.slide(color='red', duration=4.0) Wait(.25) with Loop(4): MovingDots() with UntilDone(): KeyPress() md = MovingDots(radius=300, scale=3, num_dots=200, motion_props=[ { "coherence": 0.25, "direction": 0, "direction_variance": 0 }, { "coherence": 0.25,
def __init__(self, txt=None, duration=10.0, base_time=None, max_resp=0, parent=None, save_log=True): super(FreeKey, self).__init__(parent=parent, duration=duration, save_log=save_log) # show the initial text if txt is None: txt = Text('??????', parent=self) else: # claim that text self.claim_child(txt) # set self as parent # like using with, but without the indentation self.__enter__() # save the starting text Set('fk_start_text',txt['shown'].text) # set base_time if base_time is None: base_time = txt['first_flip']['time'] # Loop until out of time or press enter Set('fk_end_time', base_time+duration) Set('fk_cur_text','') with Loop(conditional=Get('fk_end_time')>Ref(gfunc=now)) as loop: # accept keyboard response (for remaining duration) kp = KeyPress(keys=asciiplus, base_time=base_time, duration=Get('fk_end_time')-Ref(gfunc=now)) # process the key # if Backspace remove the end if_backspace = If((kp['pressed'] == 'BACKSPACE')) with if_backspace.true_state: # if there's text with If(Get('fk_cur_text')!='').true_state: # delete last char Set('fk_cur_text',Get('fk_cur_text')[:-1]) # update the text Update(txt, 'text', Get('fk_cur_text')) with if_backspace.false_state: # see if Enter if_enter = If((kp['pressed'] == 'ENTER')|(kp['pressed']=='RETURN')) with if_enter.true_state: # is Enter, so log Log(first_key_time=Get('fk_first_time'), enter_key_time=kp['press_time'], response=Get('fk_cur_text')) # start over Set('fk_cur_text','') Update(txt, 'text', Get('fk_start_text')) with if_enter.false_state: # is a new letter, so process it # if first letter, then save the time If(Get('fk_cur_text')=='', Set('fk_first_time',kp['press_time'])) # else normal letter, append it (processing SPACE) If(kp['pressed']=='SPACE', Set('fk_cur_text', Get('fk_cur_text')+' '), Set('fk_cur_text', Get('fk_cur_text')+kp['pressed'])) # update the text Update(txt, 'text', Get('fk_cur_text')) # log if anything was there and not complete If(Get('fk_cur_text')!='', Log(first_key_time=Get('fk_first_time'), enter_key_time=0.0, response=Get('fk_cur_text'))) # remove the text cause we're done Unshow(txt) # pop off self as parent self.__exit__(None,None,None)
exp = Experiment() Wait(1.0) Beep(freq=[440, 500, 600], volume=0.1, duration=1.0) Beep(freq=880, volume=0.1, duration=1.0) with Parallel(): Beep(freq=440, volume=0.1, duration=2.0) with Serial(): Wait(1.0) Beep(freq=880, volume=0.1, duration=2.0) Wait(1.0) with Meanwhile(): Beep(freq=500, volume=0.1) Beep(freq=900, volume=0.1, duration=1.0) SoundFile("test_sound.wav") SoundFile("test_sound.wav", stop=1.0) Wait(1.0) SoundFile("test_sound.wav", loop=True, duration=3.0) Wait(1.0) SoundFile("test_sound.wav", start=0.5) rec = RecordSoundFile() with UntilDone(): with Loop(3): Beep(freq=[440, 500, 600], volume=0.1, duration=1.0) Beep(freq=880, volume=0.1, duration=1.0) Wait(1.0) SoundFile(rec.filename) Wait(1.0) exp.run()
def cancel(self, cancel_time): super(RecordSoundFile, self).cancel(cancel_time) clock.unschedule(self._stop_recording) clock.schedule(self._stop_recording, event_time=self._end_time) if __name__ == '__main__': from experiment import Experiment from state import Parallel, Wait, Serial, Meanwhile, UntilDone, Loop exp = Experiment() Wait(1.0) with Loop([440, 500, 600, 880]) as l: Beep(freq=l.current, volume=0.4, duration=1.0) Beep(freq=[440, 500, 600], volume=0.1, duration=1.0) Beep(freq=880, volume=0.1, duration=1.0) with Parallel(): Beep(freq=440, volume=0.1, duration=2.0) with Serial(): Wait(1.0) Beep(freq=880, volume=0.1, duration=2.0) Wait(1.0) with Meanwhile(): Beep(freq=500, volume=0.1) Beep(freq=900, volume=0.1, duration=1.0) SoundFile("test_sound.wav") SoundFile("test_sound.wav", stop=1.0)
Wait(1.0) rect.center = exp.screen.right_bottom Wait(1.0) rect.center = exp.screen.left_top Wait(1.0) rect.center = exp.screen.left_bottom Wait(1.0) rect.center = exp.screen.center Wait(1.0) rect.slide(center=exp.screen.right_top, duration=2.0) rect.slide(center=exp.screen.right_bottom, duration=2.0) rect.slide(center=exp.screen.left_top, duration=2.0) rect.slide(center=exp.screen.left_bottom, duration=2.0) rect.slide(center=exp.screen.center, duration=2.0) with Loop(3) as loop: Video(source="test_video.mp4", size=exp.screen.size, allow_stretch=loop.i % 2, duration=5.0) with ButtonPress(): Button(text="Click to continue", size=(exp.screen.width / 4, exp.screen.height / 4)) with Meanwhile(): Triangle(points=[0, 0, 500, 500, 0, 500], color=(1.0, 1.0, 0.0, 0.5)) bez = Bezier(segments=200, color="yellow", loop=True, points=[0, 0, 200, 200, 200, 100, 100, 200, 500, 500])
def FreeKey(self, lbl, max_duration=10.0, max_resp=100, base_time=None): """ Perform free recall typed responses. Parameters ---------- lbl : Label state The text that will appear on the screen to indicate to the participant that they are to type a response. This text will disappear from the screen when a response is begun and return when ready for the next response. It's a good idea to use something like a label with '???????'. max_duration : {10.0, float} The amount of time in seconds that the participant is given to respond. max_resp : {100, int} Maximum number of responses that the participant is allowed to enter. base_time : float Manually set a time reference for the start of the state. This will be used to calculate reaction times. Example -------- FreeKey(Label('???????'), max_duration=15.0) The message '??????' will appear on the screen, and participants will be given 15 seconds to enter a response, replacing that text. They can enter as many responses as possible in the 15 second time period. Log Parameters --------------- All parameters above and below are available to be accessed and manipulated within the experiment code, and will be automatically recorded in the state.yaml and state.csv files. Refer to State class docstring for additional logged parameters. responses : list List of typed responses, each with the following information: first_key_time, first_key_rt, enter_key_time, enter_key_rt, response, response_num. The time is the actual time, the rt is the time since the base_time. """ # I'd like the lbl to be up until the below is done. How? # is it just that I would cancel it at the end here? #lbl = Label(text=txt, font_size=40) self.claim_child(lbl) with UntilDone(): # container for responses self.responses = [] # info for each response self.fk_num_resp = 0 self.fk_first_key_time = 0 self.fk_first_key_rt = 0 self.fk_cur_resp = '' # save the starting text and base time self.fk_start_text = lbl.text # handle starting values self.max_duration = max_duration self.max_resp = max_resp # handle the base time with If(base_time): # use the passed value self.base_time = base_time with Else(): # make sure it's available #Debug(fk_on_screen=lbl.on_screen) Wait(until=lbl.on_screen) #Debug(fk_on_screen=lbl.on_screen) # use the label's appear time self.base_time = lbl.appear_time['time'] # reset timing to the desired base_time ResetClock(self.base_time) # collect responses for the desired max_duration or max_resp with Loop(): # accept a key response, time is based on label's ontime kp = KeyPress(keys=asciiplus, base_time=self.base_time) # process the key with If(kp.pressed == 'BACKSPACE'): # if there is text, remove a char with If(self.fk_cur_resp != ''): self.fk_cur_resp = self.fk_cur_resp[:-1] lbl.text = self.fk_cur_resp with Elif(kp.pressed == 'ENTER'): # if there is text, log as a response # increment the response counter self.fk_num_resp += 1 # append the response to the list self.responses += [ Ref(dict, response=self.fk_cur_resp, response_num=self.fk_num_resp, first_key_time=self.fk_first_key_time, first_key_rt=self.fk_first_key_rt, enter_key_time=kp.press_time, enter_key_rt=kp.rt) ] # set starting text back and reset text self.fk_cur_resp = '' with If(self.fk_num_resp < self.max_resp): # gonna keep going lbl.text = self.fk_start_text with Else(): # new key, so append it # if it's first key, save the time with If(self.fk_cur_resp == ''): self.fk_first_key_rt = kp.rt self.fk_first_key_time = kp.press_time # append the text with If(kp.pressed == 'SPACEBAR'): # handle the space self.fk_cur_resp += ' ' with Else(): # just append the letter self.fk_cur_resp += kp.pressed # update the label lbl.text = self.fk_cur_resp with UntilDone(): Wait(max_duration, until=(self.fk_num_resp >= max_resp)) # ran out of time, see if there is an unfinished response with If(self.fk_cur_resp != ''): # there is something, so log it, too # increment the response counter self.fk_num_resp += 1 # append the response to the list, but with no Enter key time self.responses += [ Ref(dict, response=self.fk_cur_resp, response_num=self.fk_num_resp, first_key_time=self.fk_first_key_time, first_key_rt=self.fk_first_key_rt, enter_key_time=None, enter_key_rt=None) ]