class Stimuli: def __init__(self, win, timing, colors, mark_mode, input_mode): self.win = win self.timing = timing self.colors = colors self.mark_mode = mark_mode self.input_mode = input_mode if self.input_mode == 'RTBox': if RTBOXLIB_EXISTS: self.RTBox = RTBox() self.RTBox.prep() else: print "RTBox drivers not found, defaulting to keyboard" self.input_mode = "Keyboard" self.calib_seq = [201, 251, 101, 151, 51, 1] self.fixation = visual.TextStim(self.win, text='+', alignHoriz='center', alignVert='center', units='norm', pos=(0, 0), height=0.3, color=[255, 255, 255], colorSpace='rgb255', wrapWidth=2) self.cue = visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(0, 0), lineWidth=15, lineColor=self.colors['blue']) self.search_keymap = {'1': 'left', '2': 'right', '3': 'invalid', '4': 'invalid'} self.search = {} self.search['top'] = visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(0, 0.2), lineWidth=15, lineColor=self.colors['red']) self.search['bot'] = visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(0, -0.2), lineWidth=15, lineColor=self.colors['green']) line_color = (255, 255, 255) self.line = {} self.line[('top', 'left')] = visual.Line(self.win, lineColor=line_color, units='height', start=(-0.06, 0.26), end=(0.06, 0.14), lineWidth=15, lineColorSpace='rgb255') self.line[('top', 'right')] = visual.Line(self.win, lineColor=line_color, units='height', start=(0.06, 0.26), end=(-0.06, 0.14), lineWidth=15, lineColorSpace='rgb255') self.line[('top', 'straight')] = visual.Line(self.win, lineColor=line_color, units='height', start=(0, 0.26), end=(0, 0.14), lineWidth=15, lineColorSpace='rgb255') self.line[('bot', 'left')] = visual.Line(self.win, lineColor=line_color, units='height', start=(-0.06, -0.14), end=(0.06, -0.26), lineWidth=15, lineColorSpace='rgb255') self.line[('bot', 'right')] = visual.Line(self.win, lineColor=line_color, units='height', start=(0.06, -0.14), end=(-0.06, -0.26), lineWidth=15, lineColorSpace='rgb255') self.line[('bot', 'straight')] = visual.Line(self.win, lineColor=line_color, units='height', start=(0, -0.26), end=(0, -0.14), lineWidth=15, lineColorSpace='rgb255') self.mem_keymap = { '1': 'blue', '2': 'yellow', '3': 'green', '4': 'red'} self.memory = [] self.memory.append(visual.TextStim(self.win, text='Which color do you remember?', font='Helvetica', alignHoriz='center', alignVert='center', units='norm', pos=(0, 0.5), height=0.1, color=[255, 255, 255], colorSpace='rgb255', wrapWidth=2)) self.memory.append(visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(-0.45, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap['1']])) self.memory.append(visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(-0.15, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap['2']])) self.memory.append(visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(0.15, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap['3']])) self.memory.append(visual.Circle(self.win, units='height', radius=0.1, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(0.45, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap['4']])) self.memory.append(visual.TextStim(self.win, text='1', font='Helvetica', alignHoriz='center', alignVert='center', units='height', pos=(-0.45, 0), height=0.1, color=[255, 255, 255], colorSpace='rgb255')) self.memory.append(visual.TextStim(self.win, text='2', font='Helvetica', alignHoriz='center', alignVert='center', units='height', pos=(-0.15, 0), height=0.1, color=[255, 255, 255], colorSpace='rgb255')) self.memory.append(visual.TextStim(self.win, text='3', font='Helvetica', alignHoriz='center', alignVert='center', units='height', pos=(0.15, 0), height=0.1, color=[255, 255, 255], colorSpace='rgb255')) self.memory.append(visual.TextStim(self.win, text='4', font='Helvetica', alignHoriz='center', alignVert='center', units='height', pos=(0.45, 0), height=0.1, color=[255, 255, 255], colorSpace='rgb255')) if not TESTING: if self.mark_mode == 'Plexon': self.plexon = PlexClient.PlexClient() self.plexon.InitClient() if not self.plexon.IsSortClientRunning(): raise Exception('Please start Sort Client to use Plexon.') print 'Using Plexon' elif self.mark_mode == 'NI-DAQ': print 'Using NI-DAQ' elif self.mark_mode == 'Photodiode': print 'Using Photodiode' else: raise Exception('Event marking mode unknown') # self.mark_event(channel) to mark events # channel 1: cue presentation # channel 2: search presentation # channel 3: WM presentation # channel 4: Subject response def close(self): if not TESTING and self.mark_mode == 'Plexon': self.plexon.CloseClient() if self.input_mode == 'RTBox': self.RTBox.close() self.mark_task('end') core.quit() def mark_task(self, status): """ Flickers sequence to identify beginning or end of each task """ if self.mark_mode == 'Photodiode': if status == 'begin': for val in self.calib_seq: self.mark_event(val) elif status == 'end': for val in reversed(self.calib_seq): self.mark_event(val) else: print "mark_task: Status type not recognized" def get_input(self, max_wait=1.0, keylist=None): if self.input_mode == 'Keyboard': key = event.waitKeys(maxWait=max_wait, keyList=keylist) if key is not None: key = key[0] time = core.getTime() elif self.input_mode == 'RTBox': event_type, time = self.RTBox.wait_press(secs=max_wait) if event_type is not None: key = event_type[0] else: key = None else: raise Exception("Unrecognized input mode") return (key, time) def mark_event(self, channel): """ Mark event using the predetermined method. Return time it took to run in order to account for non-instantaneous marking on the photodiode. """ timer = core.Clock() if not TESTING: if self.mark_mode == 'Plexon': self.plexon.MarkEvent(channel) elif self.mark_mode == 'NI-DAQ': if channel == 2 or channel == 3: makepulse() elif self.mark_mode == 'Photodiode': self.flicker(channel) return timer.getTime() def flicker(self, value): """ Send a binary signal (value) to the photodiode by flickering a white circle in the bottom right hand corner. """ circle = visual.Circle(self.win, units='height', radius=0.05, fillColorSpace='rgb255', lineColorSpace='rgb255', fillColor=(0, 0, 0), pos=(0.73, 0.42), lineColor=(0, 0, 0)) value = np.binary_repr(value) # zero pad to 8 bits and add stop and start bits value = '1' + (8 - len(value)) * '0' + value + '1' # draw bits for bit in value: if bit == '1': circle.fillColor = (255, 255, 255) circle.draw() if bit == '0': circle.fillColor = (0, 0, 0) circle.draw() self.win.flip(clearBuffer=False) # clear circle on both buffers circle.fillColor = (0, 0, 0) circle.draw() self.win.flip(clearBuffer=False) circle.draw() def draw_fixation(self): self.fixation.draw() self.win.flip() core.wait(self.timing['fixation']) self.win.flip() def draw_cue(self, color): text = visual.TextStim(self.win, text='Remember this color!', font='Helvetica', alignHoriz='center', alignVert='center', units='norm', pos=(0, 0.5), height=0.1, color=[255, 255, 255], colorSpace='rgb255', wrapWidth=2) self.cue.lineColor = self.colors[color] draw_objs = [text, self.cue] map(autoDraw_on, draw_objs) self.win.flip() offset = self.mark_event(1) core.wait(self.timing['cue'] - offset) cue_off = core.getTime() map(autoDraw_off, draw_objs) self.win.flip() self.win.flip() core.wait(self.timing['delay']) return cue_off def do_search(self, trial): self.draw_fixation() draw_objs = [] # draw lines and circles if trial['target_pos'] == 'top': self.search['top'].lineColor = self.colors[ trial['search_colors'][0]] draw_objs.append(self.search['top']) self.search['bot'].lineColor = self.colors[ trial['search_colors'][1]] draw_objs.append(self.search['bot']) draw_objs.append(self.line[('bot', 'straight')]) else: self.search['top'].lineColor = self.colors[ trial['search_colors'][1]] draw_objs.append(self.search['top']) self.search['bot'].lineColor = self.colors[ trial['search_colors'][0]] draw_objs.append(self.search['bot']) draw_objs.append(self.line[('top', 'straight')]) draw_objs.append(self.line[(trial['target_pos'], trial['target_type'])]) map(autoDraw_on, draw_objs) search_start = core.getTime() self.win.flip() offset = self.mark_event(2) key, resp_time = self.get_input(max_wait=self.timing['search'] - offset, keylist=self.search_keymap.keys() + ['escape']) if key is None: pass elif key == 'escape': self.close() else: map(autoDraw_off, draw_objs) self.win.flip() self.win.flip() offset = self.mark_event(4) return (self.search_keymap[key], search_start, resp_time, resp_time) map(autoDraw_off, draw_objs) off_time = core.getTime() self.win.flip() self.win.flip() key, resp_time = self.get_input(max_wait=self.timing['blank'], keylist=self.search_keymap.keys() + ['escape']) if key is None: return ('timeout', search_start, off_time, resp_time) elif key == 'escape': self.close() else: offset = self.mark_event(4) return (self.search_keymap[key], search_start, off_time, resp_time) def do_memory(self): map(autoDraw_on, self.memory) start_time = core.getTime() self.win.flip() offset = self.mark_event(3) key, resp_time = self.get_input(max_wait=self.timing['WM'] - offset, keylist=self.mem_keymap.keys() + ['escape']) map(autoDraw_off, self.memory) self.win.flip() self.win.flip() if key is None: return ('timeout', start_time, resp_time) elif key == 'escape': self.close() else: offset = self.mark_event(4) return (self.mem_keymap[key], start_time, resp_time) def text_and_stim_keypress(self, text, stim=None, max_wait=float('inf')): if stim is not None: if type(stim) == list: map(lambda x: x.draw(), stim) else: stim.draw() display_text = visual.TextStim(self.win, text=text, font='Helvetica', alignHoriz='center', alignVert='center', units='norm', pos=(0, -0.8), height=0.1, color=[255, 255, 255], colorSpace='rgb255', wrapWidth=2) display_text.draw() self.win.flip() key = event.waitKeys(maxWait=max_wait) if key is not None: if key[0] == 'escape': self.close() self.win.flip() def text(self, text): display_text = visual.TextStim(self.win, text=text, font='Helvetica', alignHoriz='center', alignVert='center', units='norm', pos=(0, 0), height=0.1, color=[255, 255, 255], colorSpace='rgb255', wrapWidth=2) display_text.draw() self.win.flip()
class Stimuli: def __init__(self, win, timing, colors, mark_mode, input_mode): self.win = win self.timing = timing self.colors = colors self.mark_mode = mark_mode self.input_mode = input_mode if self.input_mode == "RTBox": if RTBOXLIB_EXISTS: self.RTBox = RTBox() self.RTBox.prep() else: print "RTBox drivers not found, defaulting to keyboard" self.input_mode = "Keyboard" self.calib_seq = [201, 251, 101, 151, 51, 1] self.fixation = visual.TextStim( self.win, text="+", alignHoriz="center", alignVert="center", units="norm", pos=(0, 0), height=0.3, color=[255, 255, 255], colorSpace="rgb255", wrapWidth=2, ) self.cue = visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(0, 0), lineWidth=15, lineColor=self.colors["blue"], ) self.search_keymap = {"1": "left", "2": "right", "3": "invalid", "4": "invalid"} self.search = {} self.search["top"] = visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(0, 0.2), lineWidth=15, lineColor=self.colors["red"], ) self.search["bot"] = visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(0, -0.2), lineWidth=15, lineColor=self.colors["green"], ) line_color = (255, 255, 255) self.line = {} self.line[("top", "left")] = visual.Line( self.win, lineColor=line_color, units="height", start=(-0.06, 0.26), end=(0.06, 0.14), lineWidth=15, lineColorSpace="rgb255", ) self.line[("top", "right")] = visual.Line( self.win, lineColor=line_color, units="height", start=(0.06, 0.26), end=(-0.06, 0.14), lineWidth=15, lineColorSpace="rgb255", ) self.line[("top", "straight")] = visual.Line( self.win, lineColor=line_color, units="height", start=(0, 0.26), end=(0, 0.14), lineWidth=15, lineColorSpace="rgb255", ) self.line[("bot", "left")] = visual.Line( self.win, lineColor=line_color, units="height", start=(-0.06, -0.14), end=(0.06, -0.26), lineWidth=15, lineColorSpace="rgb255", ) self.line[("bot", "right")] = visual.Line( self.win, lineColor=line_color, units="height", start=(0.06, -0.14), end=(-0.06, -0.26), lineWidth=15, lineColorSpace="rgb255", ) self.line[("bot", "straight")] = visual.Line( self.win, lineColor=line_color, units="height", start=(0, -0.26), end=(0, -0.14), lineWidth=15, lineColorSpace="rgb255", ) self.mem_keymap = {"1": "blue", "2": "yellow", "3": "green", "4": "red"} self.memory = [] self.memory.append( visual.TextStim( self.win, text="Which color do you remember?", font="Helvetica", alignHoriz="center", alignVert="center", units="norm", pos=(0, 0.5), height=0.1, color=[255, 255, 255], colorSpace="rgb255", wrapWidth=2, ) ) self.memory.append( visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(-0.45, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap["1"]], ) ) self.memory.append( visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(-0.15, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap["2"]], ) ) self.memory.append( visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(0.15, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap["3"]], ) ) self.memory.append( visual.Circle( self.win, units="height", radius=0.1, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(0.45, 0), lineWidth=15, lineColor=self.colors[self.mem_keymap["4"]], ) ) self.memory.append( visual.TextStim( self.win, text="1", font="Helvetica", alignHoriz="center", alignVert="center", units="height", pos=(-0.45, 0), height=0.1, color=[255, 255, 255], colorSpace="rgb255", ) ) self.memory.append( visual.TextStim( self.win, text="2", font="Helvetica", alignHoriz="center", alignVert="center", units="height", pos=(-0.15, 0), height=0.1, color=[255, 255, 255], colorSpace="rgb255", ) ) self.memory.append( visual.TextStim( self.win, text="3", font="Helvetica", alignHoriz="center", alignVert="center", units="height", pos=(0.15, 0), height=0.1, color=[255, 255, 255], colorSpace="rgb255", ) ) self.memory.append( visual.TextStim( self.win, text="4", font="Helvetica", alignHoriz="center", alignVert="center", units="height", pos=(0.45, 0), height=0.1, color=[255, 255, 255], colorSpace="rgb255", ) ) if not TESTING: if self.mark_mode == "Plexon": self.plexon = PlexClient.PlexClient() self.plexon.InitClient() if not self.plexon.IsSortClientRunning(): raise Exception("Please start Sort Client to use Plexon.") print "Using Plexon" elif self.mark_mode == "NI-DAQ": print "Using NI-DAQ" elif self.mark_mode == "Photodiode": print "Using Photodiode" else: raise Exception("Event marking mode unknown") # self.mark_event(channel) to mark events # channel 1: cue presentation # channel 2: search presentation # channel 3: WM presentation # channel 4: Subject response def close(self): if not TESTING and self.mark_mode == "Plexon": self.plexon.CloseClient() if self.input_mode == "RTBox": self.RTBox.close() self.mark_task("end") core.quit() def mark_task(self, status): """ Flickers sequence to identify beginning or end of each task """ if self.mark_mode == "Photodiode": if status == "begin": for val in self.calib_seq: self.mark_event(val) elif status == "end": for val in reversed(self.calib_seq): self.mark_event(val) else: print "mark_task: Status type not recognized" def get_input(self, max_wait=1.0, keylist=None): if self.input_mode == "Keyboard": key = event.waitKeys(maxWait=max_wait, keyList=keylist) if key is not None: key = key[0] time = core.getTime() elif self.input_mode == "RTBox": event_type, time = self.RTBox.wait_press(secs=max_wait) if event_type is not None: key = event_type[0] else: key = None else: raise Exception("Unrecognized input mode") return (key, time) def mark_event(self, channel): """ Mark event using the predetermined method. Return time it took to run in order to account for non-instantaneous marking on the photodiode. """ timer = core.Clock() if not TESTING: if self.mark_mode == "Plexon": self.plexon.MarkEvent(channel) elif self.mark_mode == "NI-DAQ": if channel == 2 or channel == 3: makepulse() elif self.mark_mode == "Photodiode": self.flicker(channel) return timer.getTime() def flicker(self, value): """ Send a binary signal (value) to the photodiode by flickering a white circle in the bottom right hand corner. """ circle = visual.Circle( self.win, units="height", radius=0.05, fillColorSpace="rgb255", lineColorSpace="rgb255", fillColor=(0, 0, 0), pos=(0.73, 0.42), lineColor=(0, 0, 0), ) value = np.binary_repr(value) # zero pad to 8 bits and add stop and start bits value = "1" + (8 - len(value)) * "0" + value + "1" # draw bits for bit in value: if bit == "1": circle.fillColor = (255, 255, 255) circle.draw() if bit == "0": circle.fillColor = (0, 0, 0) circle.draw() self.win.flip(clearBuffer=False) # clear circle on both buffers circle.fillColor = (0, 0, 0) circle.draw() self.win.flip(clearBuffer=False) circle.draw() def draw_fixation(self): self.fixation.draw() self.win.flip() core.wait(self.timing["fixation"]) self.win.flip() def draw_cue(self, color): text = visual.TextStim( self.win, text="Remember this color!", font="Helvetica", alignHoriz="center", alignVert="center", units="norm", pos=(0, 0.5), height=0.1, color=[255, 255, 255], colorSpace="rgb255", wrapWidth=2, ) self.cue.lineColor = self.colors[color] draw_objs = [text, self.cue] map(autoDraw_on, draw_objs) self.win.flip() offset = self.mark_event(1) core.wait(self.timing["cue"] - offset) cue_off = core.getTime() map(autoDraw_off, draw_objs) self.win.flip() self.win.flip() core.wait(self.timing["delay"]) return cue_off def do_search(self, trial): self.draw_fixation() draw_objs = [] # draw lines and circles if trial["target_pos"] == "top": self.search["top"].lineColor = self.colors[trial["search_colors"][0]] draw_objs.append(self.search["top"]) self.search["bot"].lineColor = self.colors[trial["search_colors"][1]] draw_objs.append(self.search["bot"]) draw_objs.append(self.line[("bot", "straight")]) else: self.search["top"].lineColor = self.colors[trial["search_colors"][1]] draw_objs.append(self.search["top"]) self.search["bot"].lineColor = self.colors[trial["search_colors"][0]] draw_objs.append(self.search["bot"]) draw_objs.append(self.line[("top", "straight")]) draw_objs.append(self.line[(trial["target_pos"], trial["target_type"])]) map(autoDraw_on, draw_objs) search_start = core.getTime() self.win.flip() offset = self.mark_event(2) key, resp_time = self.get_input( max_wait=self.timing["search"] - offset, keylist=self.search_keymap.keys() + ["escape"] ) if key is None: pass elif key == "escape": self.close() else: map(autoDraw_off, draw_objs) self.win.flip() self.win.flip() offset = self.mark_event(4) return (self.search_keymap[key], search_start, resp_time, resp_time) map(autoDraw_off, draw_objs) off_time = core.getTime() self.win.flip() self.win.flip() key, resp_time = self.get_input(max_wait=self.timing["blank"], keylist=self.search_keymap.keys() + ["escape"]) if key is None: return ("timeout", search_start, off_time, resp_time) elif key == "escape": self.close() else: offset = self.mark_event(4) return (self.search_keymap[key], search_start, off_time, resp_time) def do_memory(self): map(autoDraw_on, self.memory) start_time = core.getTime() self.win.flip() offset = self.mark_event(3) key, resp_time = self.get_input( max_wait=self.timing["WM"] - offset, keylist=self.mem_keymap.keys() + ["escape"] ) map(autoDraw_off, self.memory) self.win.flip() self.win.flip() if key is None: return ("timeout", start_time, resp_time) elif key == "escape": self.close() else: offset = self.mark_event(4) return (self.mem_keymap[key], start_time, resp_time) def text_and_stim_keypress(self, text, stim=None, max_wait=float("inf")): if stim is not None: if type(stim) == list: map(lambda x: x.draw(), stim) else: stim.draw() display_text = visual.TextStim( self.win, text=text, font="Helvetica", alignHoriz="center", alignVert="center", units="norm", pos=(0, -0.8), height=0.1, color=[255, 255, 255], colorSpace="rgb255", wrapWidth=2, ) display_text.draw() self.win.flip() key = event.waitKeys(maxWait=max_wait) if key is not None: if key[0] == "escape": self.close() self.win.flip() def text(self, text): display_text = visual.TextStim( self.win, text=text, font="Helvetica", alignHoriz="center", alignVert="center", units="norm", pos=(0, 0), height=0.1, color=[255, 255, 255], colorSpace="rgb255", wrapWidth=2, ) display_text.draw() self.win.flip()