def __init__(self, psychopy_disp, density=16.7, dot_speed=5.0, frame_rate=60, field_size=5.0, field_scale=1.1): self.dot_speed = dot_speed self.frame_rate = frame_rate self.field_size = field_size field_width = field_size * field_scale self.n_dots = int(np.ceil(density * field_width**2 / frame_rate)) # due to ElementArrayStim limitations, n_dots has to be divisible by n_sequences # so we artificially add extra dots in case it isn't divisible # (a couple of extra dots won't be a problem) self.n_dots += (self.n_sequences - self.n_dots % self.n_sequences) % self.n_sequences n_elements = self.n_dots / self.n_sequences if (n_elements * self.n_sequences != self.n_dots): raise ValueError( 'Check n_elements parameter provided to ElementArrayStim! ' 'It should be equal to n_dots/self.n_sequences, where n_dots is ' 'calculated based on density, frame rate and field width.') self.dot_stim = visual.ElementArrayStim(psychopy_disp, elementTex=None, fieldShape='circle', elementMask='circle', sizes=0.06, nElements=n_elements, units='deg', fieldSize=field_size)
def __init__(self, win, length=21, size=3, max_alpha=0.5): self.win = win location = [0, 0] # generate loc array loc = np.array(location) + np.array((size, size)) // 2 # array of rgbs for each element (2D) colors = np.ones((length ** 2, 3)) colors[::2] = 0 # array of coordinates for each element xys = [] # populate xys low, high = length // -2, length // 2 for y in range(low, high): for x in range(low, high): xys.append((size * x, size * y)) self.stim = visual.ElementArrayStim(win, xys=xys, fieldPos=loc, colors=colors, nElements=length ** 2, elementMask=None, elementTex=None, opacities=max_alpha, sizes=(size, size)) self.stim.size = (size * length, size * length)
def test_element_array_colors(): # Create element array with two elements covering the whole window in two block colours obj = visual.ElementArrayStim(win, units="pix", fieldPos=(0, 0), fieldSize=(128, 128), fieldShape='square', nElements=2, sizes=[[64, 128], [64, 128]], xys=[[-32, 0], [32, 0]], elementMask=None, elementTex=None) # Iterate through color sets for colorSet in exemplars + tykes: for space in colorSet: if space not in colors.strSpaces and not isinstance( colorSet[space], (str, type(None))): # Check that setting color arrays renders correctly obj.colorSpace = space col1 = np.array(colorSet[space]).reshape((1, -1)) col2 = getattr(colors.Color('black'), space).reshape((1, -1)) obj.colors = np.append( col1, col2, 0 ) # Set first color to current color set, second to black in same color space obj.opacity = 1 # Fix opacity at full as this is not what we're testing win.flip() obj.draw() utils.comparePixelColor(win, colors.Color(colorSet[space], space), coord=(10, 10)) utils.comparePixelColor(win, colors.Color('black'), coord=(10, 100))
def test_element_array(self): win = self.win if not win._haveShaders: pytest.skip( "ElementArray requires shaders, which aren't available") #using init thetas = numpy.arange(0, 360, 10) N = len(thetas) radii = numpy.linspace(0, 1.0, N) * self.scaleFactor x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x, y]).transpose() spiral = visual.ElementArrayStim(win, opacities=0, nElements=N, sizes=0.5 * self.scaleFactor, sfs=1.0, xys=xys, oris=-thetas) spiral.draw() #check that the update function is working by changing vals after first draw() call spiral.opacities = 1.0 spiral.sfs = 3.0 spiral.draw() "{}".format(spiral) #check that str(xxx) is working win.flip() spiral.draw() utils.compareScreenshot('elarray1_%s.png' % (self.contextName), win) win.flip()
def draw_stimuli(self): """ This function will draw the dots on the screen using the above initialized parameters. """ self.stim = visual.ElementArrayStim( self.win, units='deg', fieldPos=(0.0, 0.0), fieldSize=(self.stimPos + self.stimRadius, self.stimPos + self.stimRadius), fieldShape='circle', nElements=self.nDisks, sizes=self.stimRadius, xys=self.loc, rgbs=None, colors=[self.white] * self.nDisks, colorSpace='rgb', opacities=1.0, depths=0, fieldDepth=0, oris=0, sfs=1.0, contrs=1, phases=0, elementTex=np.random.random((self.tGrain, self.tGrain)), elementMask='circle', texRes=128, interpolate=True, name=None, autoLog=None, maskParams=None)
def createNoise(proportnNoise,win,fieldWidthPix,noiseColor): #noiseColor, assumes that colorSpace='rgb', triple between -1 and 1 numDots = int(proportnNoise*fieldWidthPix*fieldWidthPix) if numDots ==0: return None #create a matrix of all possible pixel locations, shuffle it, pick off the first numDots ones #0,0 is center of field possibleXcoords = -fieldWidthPix/2 + np.arange(fieldWidthPix) possibleXcoords += fieldWidthPix/30 #adding one-tenth because for some mysterious reason not centered, I guess letters aren't drawn centered possibleYcoords = deepcopy(possibleXcoords) #allFieldCoords = expandgrid(possibleXcoords,possibleYcoords) allFieldCoords = expandGridNumpy( np.array([ possibleXcoords, possibleYcoords] ) ) #numpy array version so that can add a constat to all the x coordinates. Can't access all the x-coordinates if it is a list of tuples, like returned by expandgrid #shuffle it np.random.shuffle(allFieldCoords) dotCoords = allFieldCoords[0:numDots] #create opacity for each dot opacs = np.ones(numDots)#all opaque verticalAdjust = 3 #number of pixels to raise rectangle by. Using only uppercase letters and seem to be drawn above the line noise = visual.ElementArrayStim(win,units='pix', elementTex=None, elementMask=None, nElements=numDots, fieldSize=[fieldWidthPix,fieldWidthPix], fieldPos=(0.0, verticalAdjust), colorSpace='rgb', colors=noiseColor, #set to black xys= dotCoords, opacities=opacs, sizes=1) return (noise,allFieldCoords,numDots) #Can just use noise, but if want to generate new noise of same coherence level quickly, can just shuffle coords
def run_scrsaver(depthBits): mon = monitors.Monitor(name='VIEWPixx LITE', width=38, distance=57) mon.setSizePix((1920, 1200)) mon.save() # if the monitor info is not saved win = visual.Window(fullscr=True, mouseVisible=False, bpc=(depthBits, depthBits, depthBits), depthBits=depthBits, monitor=mon) kb = keyboard.Keyboard() if depthBits == 8: colorSpace = 'rgb255' elif depthBits == 10: colorSpace = 'rgb' else: raise ValueError("Invalid color depth!") while True: num = np.random.randint(5, high=10) rect = visual.ElementArrayStim(win, units='norm', nElements=num ** 2, elementMask=None, elementTex=None, sizes=(2 / num, 2 / num), colorSpace=colorSpace) rect.xys = [(x, y) for x in np.linspace(-1, 1, num, endpoint=False) + 1 / num for y in np.linspace(-1, 1, num, endpoint=False) + 1 / num] rect.colors = [ColorPicker(depthBits=depthBits, unit='deg').newcolor(x)[1] for x in np.random.randint(0, high=360, size=num ** 2)] rect.draw() win.mouseVisible = False win.flip() kb.clock.reset() if kb.getKeys(): # press any key to quit core.quit() else: time.sleep(3) # change every 3 sec
def patch_stim(self): # standard and test stimuli patch = visual.ElementArrayStim(win=self.win, units='deg', nElements=self.patch_nmb, elementMask='circle', elementTex=None, sizes=self.cfg['patch_size'], colorSpace=self.ColorSpace) return patch
def patchstim(patchsize=0.5): patch = visual.ElementArrayStim(win=win, units='deg', nElements=npatch, elementMask='circle', elementTex=None, sizes=patchsize, colorSpace='rgb255') return patch
def generate_texture(self): xys = self.element_position # for _ in range(self.number): # xys.append([0, 0]) # Placeholder for now, because we'll set the real places later texture = (visual.ElementArrayStim( win=self.Renderer.display_window, fieldSize=self.Renderer.window_size(), elementMask=None, nElements=self.number, xys=xys, sizes=self.size, elementTex=self.source_image)) return texture
def new_array(self): """Initialize new stick positions.""" initial_xys = self.poisson_disc_sample() n_sticks = len(initial_xys) sticks = visual.ElementArrayStim(self.win, xys=initial_xys, nElements=n_sticks, elementTex=None, elementMask="sqr", sizes=self.stick_sizes, autoLog=False) self.sticks = sticks self.n = n_sticks
def patch_stim(self, xlim, ylim): # standard and test stimuli n = int(np.sqrt(self.patch_nmb)) pos = [[x, y] for x in np.linspace(xlim[0], xlim[1], n) for y in np.linspace(ylim[0], ylim[1], n)] patch = visual.ElementArrayStim(win=self.win, units='deg', fieldSize=self.cfg['field_size'], xys=pos, nElements=self.patch_nmb, elementMask='circle', elementTex=None, sizes=self.cfg['patch_size'], colorSpace=self.ColorSpace) return patch
def make_ring(self, text_size=45): """ create the ring 20210518 - use images instead to match eprime experiment makes self.ringimg['rew'] and self.ringimg['neu'] see https://discourse.psychopy.org/t/the-best-way-to-draw-many-text-objects-rsvp/2758 """ # color and symbol for ring reward cues = { 'neu': { 'color': 'gray', 'sym': '#' }, 'rew': { 'color': 'green', 'sym': '$' } } n_in_ring = 12 el_rs = 250 # TODO: make relative to screen size? el_thetas = np.linspace(0, 360, n_in_ring, endpoint=False) el_xys = np.array(misc.pol2cart(el_thetas, el_rs)).T ringtext = visual.TextStim(win=self.win, units='pix', bold=True, height=text_size, text='$') # '$' will be changed cap_rect_norm = [ -(text_size / 2.0) / (self.win.size[0] / 2.0), # left +(text_size / 2.0) / (self.win.size[1] / 2.0), # top +(text_size / 2.0) / (self.win.size[0] / 2.0), # right -(text_size / 2.0) / (self.win.size[1] / 2.0) # bottom ] for k in ['rew', 'neu']: ringtext.text = cues[k]['sym'] ringtext.color = cues[k]['color'] buff = visual.BufferImageStim(win=self.win, stim=[ringtext], rect=cap_rect_norm) # img = (np.flipud(np.array(buff.image)[..., 0]) / 255.0 * 2.0 - 1.0) self.ringimg[k] = visual.ElementArrayStim( win=self.win, units="pix", nElements=n_in_ring, sizes=buff.image.size, xys=el_xys, # colors=cues[k]['color'], elementMask=None, elementTex=buff.image)
def __init__(self): myDlg = gui.Dlg(title="Wisconsin Card Sorting Task",pos=(SZ[0]/2,SZ[1]/2)) myDlg.addField('Subject ID:',1) #myDlg.addField('Number of Trials:',128) myDlg.show()#show dialog and wait for OK or Cancel vpInfo = myDlg.data self.vp = vpInfo[0] self.win = visual.Window(size=SZ,units='deg',fullscr=False,monitor=MON) self.mouse = event.Mouse(True,None,self.win) self.cards = [] self.elems = [] for i in range(4): self.cards.append(visual.Rect(self.win,CARDW,CARDH,fillColor='white', pos = ((i-1.5)*(CARDX+CARDW),CARDY),lineColor='black',interpolate=False)) self.elems.append(visual.ElementArrayStim(self.win,nElements=4,sizes=1.5,colors='black', fieldPos = ((i-1.5)*(CARDX+CARDW),CARDY),elementTex=None)) # Add the probe card to the screen self.cards.append(visual.Rect(self.win,CARDW,CARDH,fillColor='white', pos = TPOS,lineColor='black',interpolate=False)) self.elems.append(visual.ElementArrayStim(self.win,nElements=4,sizes=1.5,colors='black', fieldPos = TPOS,elementTex=None)) # Make the piles for i in range(4): self.cards.append(visual.Rect(self.win,CARDW,CARDH,fillColor='grey', pos = ((i-1.5)*(CARDX+CARDW),PrevCARDY),lineColor='black',interpolate=False)) self.elems.append(visual.ElementArrayStim(self.win,nElements=4,sizes=1.5,colors='grey', fieldPos = ((i-1.5)*(CARDX+CARDW),PrevCARDY),elementTex=None)) self.text = visual.TextStim(self.win,pos=FPOS,height=2) if not os.path.exists('data'): os.makedirs('data') fname = os.path.join('data', 'wcst_s%03d_%s.csv' % (self.vp, time.strftime("%Y%m%d-%H%M%S"))) self.output = open(fname, 'w') self.output.write('PartID\tTrialNum\tCard\tRule\tRespTime\tCorrect\n')
def random_dot_motion(self, task_instance): clock = core.Clock() while clock.getTime() < STIMULUS_TIME: self.central_circle.draw() dots = task_instance.update_dots() visual.ElementArrayStim( win=self.win, nElements=len(dots), elementTex=None, elementMask="gauss", xys=[dot.xy for dot in dots], sizes=15, colors=WHITE, ).draw() self.win.flip() task_instance.move_dots()
def make_tokens(xys, indices, pos): """Creates an elementArrayStim based on given parameters""" # Select xys if len(xys) == len(indices): this_xys = xys #no need to select indices else: this_xys = [xys[i] for i in indices] #find corresponding x's,y's # Create the central ElementArrayStim array tokens = visual.ElementArrayStim(win, xys=this_xys, fieldShape='circle', fieldPos=pos, colors=whitish, nElements=len(this_xys), elementMask='circle', elementTex=None, sizes=(token_size[0], token_size[1])) return tokens
def setElements(self, name='default', texture='square', mask=None, nElements=None, sizes=None, xys=None, oris=None, sfs=None, phases=None, colors=None, opacities=None, contrs=None): """ Private wrapper for Psychopy ElementArrayStim. :param name: element array name :param texture: texture to render, could be string or numpy array. If string, right now support 'square' or 'rectangle' :param mask: mask to mask texture, should be numpy array or None. :param nElements: the number of elements to render. :param sizes: the size of elements, (nElements, 2) in pixel unit. :param xys: the position of elements, (nElements, 2) in pixel unit. :param oris: the orientation of elements, (nElements,) :param sfs: reserved :param phases: reserverd :param colors: the color of elements, (nElements, 3) :param opacities: the opacity of elements, (nElements,) :param contrs: the contrast of elements, (nElements,) :return: """ if type(texture) is str: tex = self._SHAPES[texture] mask = None self.els[name] = visual.ElementArrayStim(self.win, units='pix', elementTex=tex, elementMask=mask, texRes=48, nElements=nElements, sizes=sizes, xys=xys, oris=oris, sfs=sfs, phases=phases, colors=colors, opacities=opacities, contrs=contrs)
def test_element_array(self): win = self.win if not win._haveShaders: pytest.skip("ElementArray requires shaders, which aren't available") #using init thetas = numpy.arange(0,360,10) N=len(thetas) radii = numpy.linspace(0,1.0,N)*self.scaleFactor x, y = misc.pol2cart(theta=thetas, radius=radii) xys = numpy.array([x,y]).transpose() spiral = visual.ElementArrayStim(win, nElements=N,sizes=0.5*self.scaleFactor, sfs=3.0, xys=xys, oris=thetas) spiral.draw() win.flip() spiral.draw() utils.compareScreenshot('elarray1_%s.png' %(self.contextName), win) win.flip()
def __init__(self, win,nDots, minDistance, maxDistance, dotSize, mu, sigma, pixPerSecond,flipcos = False): self.win = win self.nDots = nDots self.minDistance = minDistance self.maxDistance = maxDistance self.dotSize = dotSize self.pixPerSecond = pixPerSecond self.mu = mu self.sigma = sigma self.rotationMatrix = np.array([[np.cos(np.pi),np.sin(np.pi)],[-np.sin(np.pi),np.cos(np.pi)]]) self.dotPositions = [] for dot in range(self.nDots): overlap = True while overlap: r = random.uniform(self.minDistance,self.maxDistance**2) randomAngle=random.uniform(0,1)*2*np.pi # calculate x and y position dot_x = np.sqrt(r)*np.cos(randomAngle) dot_y = np.sqrt(r)*np.sin(randomAngle) if not self.dotPositions: break diff = np.array(self.dotPositions) - np.array([dot_x,dot_y]) tmp = abs(diff) < self.dotSize if not True in tmp[:,1] & tmp[:,0]: overlap = False # append to list self.dotPositions.append([dot_x, dot_y]) self.dotPositions = np.array(self.dotPositions) if self.sigma == 0: dotDirections = np.array(self.nDots*[self.mu]) else: dotDirections = np.random.normal(self.mu,self.sigma,self.nDots) if flipcos: self.dotVelocities = np.column_stack((np.sin(np.deg2rad(dotDirections)),np.cos(np.deg2rad(dotDirections)))) else: self.dotVelocities = np.column_stack((np.cos(np.deg2rad(dotDirections)),np.sin(np.deg2rad(dotDirections)))) #create stimulus self.stim = visual.ElementArrayStim(self.win, elementTex = 'none',elementMask = 'circle', nElements=self.nDots, sizes=self.dotSize, xys = self.dotPositions,colors = (1,1,1),contrs = 0.5)
def update_cal_target(self): ''' make sure target stimuli is already memory when being used by draw_cal_target ''' if self.calTarget is 'picture': if self.pictureTargetFile is None: print( 'ERROR: Clibration target is None, please provide a picture' ) core.quit() else: self.calibTar = visual.ImageStim(self.display, self.pictureTargetFile, size=self.targetSize) elif self.calTarget is 'spiral': thetas = numpy.arange(0, 1440, 10) N = len(thetas) radii = numpy.linspace(0, 1.0, N) * self.targetSize x, y = pol2cart(theta=thetas, radius=radii) xys = numpy.array([x, y]).transpose() self.calibTar = visual.ElementArrayStim(self.display, nElements=N, sizes=self.targetSize, sfs=3.0, xys=xys, oris=-thetas) elif self.calTarget is 'movie': if self.movieTargetFile is None: print( 'ERROR: Clibration target is None, please provide a movie clip' ) core.quit() else: self.calibTar = visual.MovieStim3(self.display, self.movieTargetFile, loop=True, size=self.targetSize) else: #'use the default 'circle' self.calibTar = visual.Circle(self.display, radius=self.targetSize / 2, lineColor=self.foregroundColor, fillColor=self.backgroundColor, lineWidth=self.targetSize / 2.0, units='pix')
def flash_init(win, position=[0, 0], square_size=10, columns=10, rows=10): global flash # The flash stimulus (an array of flashing squares) red = [1, -1, -1] green = [-1, 1, -1] blue = [-1, -1, 1] yellow = [1, 0.97, -0.55] black = [-1, -1, -1] color_set = [red, green, blue, yellow, black] cell_number = columns * rows by_color = int(np.floor(float(cell_number) / len(color_set))) # fill an array with colors. Each color should appear approximatively the same number of times. f_colors = [] for c in color_set: for i in range(by_color): f_colors.append(c) shuffle(color_set) i = cell_number - len(f_colors) while i > 0: f_colors.append(color_set[i]) i -= 1 # randomize color order. shuffle(f_colors) # fill an array with coordinate for each color square. First square should be at the upper left # and next should follow from left to right and up to down. xys = [] x_left = (1 - columns) * square_size / 2 y_top = (1 - rows) * square_size / 2 for l in range(rows): for c in range(columns): xys.append((x_left + c * square_size, y_top + l * square_size)) flash = visual.ElementArrayStim(win=win, fieldPos=position, fieldShape='sqr', nElements=cell_number, sizes=square_size, xys=xys, colors=f_colors, elementTex=None, elementMask=None, name='flash', autoLog=False)
def make_stimulus(self): self.stimulus = visual.ElementArrayStim( self.screen, elementTex='sqr', elementMask='raisedCos', maskParams={'fringeWidth': 0.6}, nElements=1, sizes=self.session.standard_parameters['stimulus_size'] * self.session.pixels_per_degree, sfs=self.session.standard_parameters['stimulus_base_spatfreq'], xys=np.array((self.trial_settings['trial_position_x'] * self.session.pixels_per_degree, self.trial_settings['trial_position_y'] * self.session.pixels_per_degree))[np.newaxis, :], oris=self.trial_settings['base_ori'], colors=ct.lab2psycho([ self.trial_settings['base_color_lum'], self.trial_settings['base_color_a'], self.trial_settings['base_color_b'] ]), colorSpace='rgb', units='pix')
def newRand(): #Anzahl der Punkte n_dots = 100000 #Position der Punkte dot_xys = [] for dot in range(n_dots): dot_x = random.uniform(-300, 100) dot_y = random.uniform(-200, 200) dot_xys.append([dot_x, dot_y]) #dot_xys = np.random.normal(0,1,[256,256]) #Gradient der Punkte randomGradient = [] for dot in range(n_dots): randomNumber = random.gauss(127.5, 100) randomGradient.append([randomNumber, randomNumber, randomNumber]) #Erstellen der Punkte dot_stim = visual.ElementArrayStim(win=v_winObj, units="pix", nElements=n_dots, elementTex=None, elementMask="gauss", xys=dot_xys, sizes=3, colors=randomGradient, colorSpace='rgb255') return dot_stim
# --- Create Stimulus Array, pre-allocate and configure square flickers number_stimulus = 5 stimulus_sizes = np.array([3] * number_stimulus) stimulus_color_ON = np.array([1, 1, 1] * number_stimulus) stimulus_color_ON = np.reshape(stimulus_color_ON, [number_stimulus, 3]) stimulus_color_OFF = stimulus_color_ON * -1 stimulus_locations = np.array([[-25, 0], [25, 0], [0, 13], [0, -13], [-25, 13]]) stimulus_array = visual.ElementArrayStim(window_handle, fieldPos=(0.0, 0.0), units='cm', fieldSize=[1920, 1080], sizes=stimulus_sizes, fieldShape='sqr', xys=stimulus_locations, nElements=number_stimulus, sfs=0, elementTex=None, elementMask=None, colors=stimulus_color_ON, colorSpace='rgb') # --- Configure execution time for the flickering loop target_time = 20 time.clock() # First clock call that serves as time reference clock_object = core.Clock() elapsed_time = clock_object.getTime() # --- Enable frame monitoring and logging (to detect drop frames) window_handle.flip()
def doRSVPStim(trial): ''' ONLY DOES ONE CUE AT THE MOMENT This function generates the stimuli for each trial. The word "frame" here refers to a set of simultaneous RSVP stimuli. I'll use "refresh" to refer to monitor refreshes. Using the parameters for the current trial: - Work out the temporal position of the cue(s) - Shuffle the order of the letters - Calculate the position and cortically-magnified size for each stream - draw and buffer preCues - Capture each stream's pixels on each frame using bufferImageStim - Collate each frame's pixels so that all stimuli are represented by the same matrix of pixels. Put the cue in there if it's the cued frame - pass the matrix of pixels to elementarraystim ''' global cue nStreams = trial['nStreams'] numTargets = trial['numToCue'] cuedFrame = trial['cue0temporalPos'] cuedStream = np.random.choice(np.arange(nStreams), 1) cue.pos = calcStreamPos( trial = trial, cueOffsets = cueOffsets, streami = cuedStream, streamOrNoise = False ) cue = corticalMagnification.corticalMagnification(cue, 0.9810000000000002, cue = True) #this is the cuesize from the original experiment preCues = list() preCues.append(cue) if trial['cueSpatialPossibilities'] == 2: preCue = visual.Circle(myWin, radius=cueRadius,#Martini used circles with diameter of 12 deg lineColorSpace = 'rgb', lineColor=letterColor, lineWidth=2.0, #in pixels units = 'deg', fillColorSpace = 'rgb', fillColor=None, #beware, with convex shapes fill colors don't work pos= [-5,-5], #the anchor (rotation and vertices are position with respect to this) interpolate=True, autoLog=False)#this stim changes too much for autologging to be useful preCue.pos = calcStreamPos( trial = trial, cueOffsets = cueOffsets, streami = cuedStream-4, streamOrNoise = False ) preCue = corticalMagnification.corticalMagnification(preCue, 0.9810000000000002, cue = True) preCues.append(preCue) elif trial['cueSpatialPossibilities'] == 8: for i in range(1,8): preCue = visual.Circle(myWin, radius=cueRadius,#Martini used circles with diameter of 12 deg lineColorSpace = 'rgb', lineColor=letterColor, lineWidth=2.0, #in pixels units = 'deg', fillColorSpace = 'rgb', fillColor=None, #beware, with convex shapes fill colors don't work pos= [-5,-5], #the anchor (rotation and vertices are position with respect to this) interpolate=True, autoLog=False)#this stim changes too much for autologging to be useful preCue.pos = (calcStreamPos( trial = trial, cueOffsets = cueOffsets, streami = cuedStream-i, streamOrNoise = False )) preCue = corticalMagnification.corticalMagnification(preCue, 0.9810000000000002, cue = True) preCues.append(preCue) print('cueFrame = ' + str(cuedFrame)) preCueStim = preTrial[int(baseAngleCWfromEast/anglesMustBeMultipleOf)] + preCues + [fixatnPoint] preCueFrame = visual.BufferImageStim( win = myWin, stim = preCueStim) preCueFrame = np.flipud(np.array(preCueFrame.image)[..., 0]) / 255.0 * 2.0 - 1.0 #Via djmannion. This converts the pixel values from [0,255] to [-1,1]. I think 0 is middle grey. I'll need to change this to match the background colour eventually preCueFrame = np.pad( array=preCueFrame, pad_width=pad_amounts, #See 'Buffered image size dimensions' section mode="constant", constant_values=0.0 ) preCueFrame =visual.ElementArrayStim( win = myWin, units = 'pix', nElements=1, xys = [[0,0]], sizes=preCueFrame.shape, elementTex=preCueFrame, elementMask = 'none' ) streamPositions = list() #Might need to pass this to elementArrayStim as xys. Might not though streamLetterIdxs = np.empty( #use an array so I can select columns (frames) for buffering. This is an empty array that will eventually have the #letter indexes for each stream. Selecting a column gives us all streams at a particular frame. Selecting a row gives us #all frames for a particular stream shape = (nStreams,numLettersToPresent), dtype = int ) streamLetterIdentities = np.empty( #Letter identities for these streams shape = (nStreams,numLettersToPresent), dtype = str ) for thisStream in xrange(nStreams): thisSequence = np.arange(24) np.random.shuffle(thisSequence) theseIdentities = [potentialLetters[idx] for idx in thisSequence] streamLetterIdxs[thisStream,:] = thisSequence streamLetterIdentities[thisStream,:] = theseIdentities #print('For stream %(streamN)d the letters are: %(theseLetters)s' % {'streamN':thisStream, 'theseLetters':''.join(theseIdentities)}) correctIdx = streamLetterIdxs[cuedStream,cuedFrame] print('correctIdx') print(correctIdx) correctLetter = alphabetHelpers.numberToLetter(correctIdx, potentialLetters) #potentialLetters is global frameStimuli = list() #A list of elementArrayStim objects, each represents a frame. Drawing one of these objects will draw the letters and the cue for that frame for thisFrame in xrange(numLettersToPresent): theseStimuli = streamLetterIdxs[:,thisFrame] #The alphabetical indexes of stimuli to be shown on this frame stimuliToDraw = list() #Can pass a list to bufferimageStim! stimuliToDraw.append(fixatn) stimuliToDrawCounterPhase = list() stimuliToDrawCounterPhase.append(fixatnCounterphase) for thisStream in xrange(nStreams): cueThisFrame = thisStream == cuedStream and thisFrame == cuedFrame #If true, draw the cue and capture that too thisLetterIdx = theseStimuli[thisStream] #The letter index for this particular stream on this particular frame thisStreamStimulus = streamTextObjects[thisStream,thisLetterIdx] #The text object for this stream thisPos = calcStreamPos( trial = trial, cueOffsets = cueOffsets, streami = thisStream, streamOrNoise = False ) thisStreamStimulus.pos = thisPos stimuliToDraw.append(thisStreamStimulus) stimuliToDrawCounterPhase.append(thisStreamStimulus) if cueThisFrame and cueType == 'exogenousRing': stimuliToDraw.append(cue) stimuliToDrawCounterPhase.append(cue) buff = visual.BufferImageStim( #Buffer these stimuli win = myWin, stim = stimuliToDraw ) buff = np.flipud(np.array(buff.image)[..., 0]) / 255.0 * 2.0 - 1.0 #Via djmannion. This converts the pixel values from [0,255] to [-1,1]. I think 0 is middle grey. I'll need to change this to match the background colour eventually buff = np.pad( array=buff, pad_width=pad_amounts, #See 'Buffered image size dimensions' section mode="constant", constant_values=0.0 ) thisFrameStimuli = visual.ElementArrayStim( #A stimulus representing this frame with the fixation at full luminance win = myWin, units = 'pix', nElements=1, xys = [[0,0]], sizes=buff.shape, elementTex=buff, elementMask = 'none' ) buff = visual.BufferImageStim( #Buffer these stimuli win = myWin, stim = stimuliToDrawCounterPhase ) buff = np.flipud(np.array(buff.image)[..., 0]) / 255.0 * 2.0 - 1.0 #Via djmannion. This converts the pixel values from [0,255] to [-1,1]. I think 0 is middle grey. I'll need to change this to match the background colour eventually buff = np.pad( array=buff, pad_width=pad_amounts, #See 'Buffered image size dimensions' section mode="constant", constant_values=0.0 ) thisFrameStimuliCounterPhase = visual.ElementArrayStim( #A stimulus representing this frame with the fixation phase reversed win = myWin, units = 'pix', nElements=1, xys = [[0,0]], sizes=buff.shape, elementTex=buff, elementMask = 'none' ) frameStimuli.append([thisFrameStimuli, thisFrameStimuliCounterPhase]) ts = [] waiting = True myMouse.setVisible(waiting) while waiting: startTrialStimuli.draw() startTrialBox.draw() myWin.flip() if myMouse.isPressedIn(startTrialBox): waiting = False myMouse.setVisible(waiting) if eyetracking: tracker.startEyeTracking(nDone,True,widthPix,heightPix) #start recording with eyetracker myWin.flip(); myWin.flip()#Make sure raster at top of screen (unless not in blocking mode), and give CPU a chance to finish other tasks preCueFrame.draw() myWin.flip() core.wait(.25) myWin.flip core.wait(.5) fixatn.draw() myWin.flip() core.wait(1) t0 = trialClock.getTime() for n in xrange(trialDurFrames): oneFrameOfStim(n, frameStimuli) myWin.flip() ts.append(trialClock.getTime() - t0) if eyetracking: tracker.stopEyeTracking() print('stopped tracking') return streamLetterIdxs, streamLetterIdentities, correctLetter, ts, cuedStream, cuedFrame
def __init__(self, session, bar_width_ratio, grid_pos): """ Initializes a Stim object. Parameters ---------- session : exptools Session object A Session object (needed for metadata) bar_width_ratio : float Ratio of screen dim to use as bar width grid_pos : array List/array of grid positions within display, to select a subset that will be the bar """ # general parameters self.session = session self.bar_width_pix = self.session.screen * bar_width_ratio self.grid_pos = grid_pos self.condition_settings = self.session.settings['stimuli'][ 'conditions'] # define element arrays here, with settings of background # will be updated later when drawing # number of elements self.nElements = self.grid_pos.shape[0] # element positions self.element_positions = self.grid_pos # element sizes element_sizes_px = tools.monitorunittools.deg2pix( self.session.settings['stimuli']['element_size'], self.session.monitor) self.element_sizes = np.ones((self.nElements)) * element_sizes_px # elements spatial frequency self.element_sfs = np.ones( (self.nElements)) * self.condition_settings['background'][ 'element_sf'] # in cycles/gabor width # element orientation (half ori1, half ori2) ori_arr = np.concatenate( (np.ones((math.floor(self.nElements * .5))) * self.condition_settings['background']['element_ori'][0], np.ones((math.ceil(self.nElements * .5))) * self.condition_settings['background']['element_ori'][1])) # add some jitter to the orientations self.element_ori = jitter( ori_arr, max_val=self.condition_settings['background']['ori_jitter_max'], min_val=self.condition_settings['background']['ori_jitter_min']) np.random.shuffle(self.element_ori) # shuffle the orientations # element contrasts self.element_contrast = np.ones( (self.nElements )) * self.condition_settings['background']['element_contrast'] # element colors self.element_color = np.ones( (int(np.round(self.nElements)), 3)) * np.array( self.condition_settings['background']['element_color']) self.session.background_array = visual.ElementArrayStim( win=self.session.win, nElements=self.nElements, units='pix', elementTex='sin', elementMask='gauss', sizes=self.element_sizes, sfs=self.element_sfs, xys=self.element_positions, oris=self.element_ori, contrs=self.element_contrast, colors=self.element_color, colorSpace=self.session.settings['stimuli']['colorSpace']) self.session.bar0_array = visual.ElementArrayStim( win=self.session.win, nElements=self.nElements, units='pix', elementTex='sin', elementMask='gauss', sizes=self.element_sizes, sfs=self.element_sfs, xys=self.element_positions, oris=self.element_ori, contrs=self.element_contrast, colors=self.element_color, colorSpace=self.session.settings['stimuli']['colorSpace'])
def run_trial(self, rot, cond, std, count): # set two reference leftRef = self.patch_ref(theta=cond['leftRef'], pos=self.cfg['leftRef.pos']) rightRef = self.patch_ref(theta=cond['rightRef'], pos=self.cfg['rightRef.pos']) # randomly assign patch positions: upper (+) or lower (-) patchpos = [self.cfg['standard.ylim'], self.cfg['test.ylim']] rndpos = patchpos.copy() np.random.shuffle(rndpos) sPatch = self.patch_stim(self.cfg['standard.xlim'], rndpos[0]) tPatch = self.patch_stim(self.cfg['test.xlim'], rndpos[1]) # set colors of two stimuli standard = cond['standard'] # standard should be fixed test = standard + rot sPatch.colors, tPatch.colors = self.choose_con(standard, test, std) # fixation cross fix = visual.TextStim(self.win, text="+", units='deg', pos=[0, 0], height=0.5, color='black', colorSpace=self.ColorSpace) # number of trial num = visual.TextStim(self.win, text="trial " + str(count), units='deg', pos=[12, -10], height=0.4, color='black', colorSpace=self.ColorSpace) trial_time_start = time.time() # first present references fix.draw() num.draw() leftRef.draw() rightRef.draw() self.win.flip() core.wait(1.0) # then present the standard and the test stimuli as well fix.draw() num.draw() leftRef.draw() rightRef.draw() sPatch.draw() tPatch.draw() self.win.flip() core.wait(self.trial_dur) fix.draw() self.win.flip() core.wait(0.2) # 0.2 sec gray background react_time_start = time.time() # refresh the window and show a colored checkerboard horiz_n = 30 vertic_n = 20 rect = visual.ElementArrayStim(self.win, units='norm', nElements=horiz_n * vertic_n, elementMask=None, elementTex=None, sizes=(2 / horiz_n, 2 / vertic_n), colorSpace=self.ColorSpace) rect.xys = [ (x, y) for x in np.linspace(-1, 1, horiz_n, endpoint=False) + 1 / horiz_n for y in np.linspace(-1, 1, vertic_n, endpoint=False) + 1 / vertic_n ] rect.colors = [ self.ColorPicker.newcolor(theta=x)[1] for x in np.random.randint(0, high=360, size=horiz_n * vertic_n) ] rect.draw() self.win.flip() core.wait(0.5) # 0.5 sec checkerboard judge = None react_time_stop = -1 kb = keyboard.Keyboard() get_keys = kb.getKeys(['right', 'left', 'escape' ]) # if response during the checkerboard if ('left' in get_keys and rot * rndpos[0][0] > 0) or ('right' in get_keys and rot * rndpos[0][0] < 0): judge = 1 # correct react_time_stop = time.time() elif ('left' in get_keys and rot * rndpos[0][0] < 0) or ('right' in get_keys and rot * rndpos[0][0] > 0): judge = 0 # incorrect react_time_stop = time.time() if 'escape' in get_keys: config_tools.write_xrl(self.subject, break_info='userbreak') core.quit() self.win.flip() fix.draw() self.win.flip() if judge is None: # if response after the checkerboard for wait_keys in event.waitKeys(): if (wait_keys == 'left' and rot * rndpos[0][0] > 0) or ( wait_keys == 'right' and rot * rndpos[0][0] < 0): judge = 1 # correct react_time_stop = time.time() elif (wait_keys == 'left' and rot * rndpos[0][0] < 0) or ( wait_keys == 'right' and rot * rndpos[0][0] > 0): judge = 0 # incorrect react_time_stop = time.time() elif wait_keys == 'escape': config_tools.write_xrl(self.subject, break_info='userbreak') core.quit() react_time = react_time_stop - react_time_start return judge, react_time, trial_time_start
# divide the dotSpeed by the refresh rate dotSpeed = dotSpeed / refr_rate # log stimulus properties defined above logFile.write('nDots=' + unicode(nDots) + '\n') logFile.write('speed=' + unicode(dotSpeed) + '\n') logFile.write('dotSize=' + unicode(dotSize) + '\n') logFile.write('fieldSizeRadius=' + unicode(FieldSizeRadius) + '\n') # initialise moving dot stimuli dotPatch = visual.ElementArrayStim(myWin, fieldPos=(0.0, 0.0), autoLog=False, elementTex=None, name='dotPatch', fieldShape='circle', elementMask='circle', nElements=int(nDots), sizes=dotSize, units='deg', fieldSize=FieldSizeRadius * 2, colors=dotColor) # fixation dot dotFix = visual.Circle( myWin, autoLog=False, name='dotFix', units='pix', radius=5, fillColor=[1.0, 0.0, 0.0], lineColor=[1.0, 0.0, 0.0],
def __init__(self, screen, trial, session, trial_params): # parameters self.trial = trial self.session = session self.screen = screen self.size_pix = session.standard_parameters[ 'stimulus_size'] * session.pixels_per_degree # self.orientation = orientation # convert to radians immediately, and use to calculate rotation matrix self.trial_params = trial_params self.orientations = [] self.positions = [] self.colors = [] self.element_array = [] for i, c in enumerate(self.trial_params): if len(c): #self.element_array.append(visual.GratingStim(self.screen, tex = 'sqr', mask = 'raisedCos', maskParams = {'fringeWidth': 0.6}, texRes = 1024, sf = self.session.standard_parameters['stimulus_base_spatfreq'], ori = c[0], units = 'pix', size = (self.size_pix, self.size_pix), pos = (self.session.stimulus_positions[i][0]*self.session.pixels_per_degree, self.session.stimulus_positions[i][1]*self.session.pixels_per_degree), colorSpace = 'rgb', color = c[1:])) # self.colors.append([rgbc*255.0 for rgbc in colorsys.hls_to_rgb(c[1], .5, 1)]) self.colors.append(c[1:]) self.positions.append((self.session.stimulus_positions[i][0] * session.pixels_per_degree, self.session.stimulus_positions[i][1] * session.pixels_per_degree)) self.orientations.append(c[0]) self.period = session.standard_parameters[ 'mapper_stimulus_duration'] * session.standard_parameters['TR'] self.refresh_frequency = self.period / session.standard_parameters[ 'mapper_n_redraws'] self.phase = 0 # bookkeeping variables self.eccentricity_bin = -1 self.redraws = 0 self.last_redraw = 0 self.frames = 0 self.last_stimulus_present_for_task = 0 # psychopy stimuli self.fix_gray_value = (0, 0, 0) # self.populate_stimulus() # make this stimulus array a session variable, in order to have to create it only once... # if not hasattr(session, 'element_array'): self.element_array = None if len(self.colors): self.element_array = visual.ElementArrayStim( screen, elementTex='sqr', elementMask='raisedCos', maskParams={'fringeWidth': 0.6}, nElements=len(self.positions), sizes=session.standard_parameters['stimulus_size'] * session.pixels_per_degree, sfs=session.standard_parameters['stimulus_base_spatfreq'], xys=self.positions, oris=self.orientations, colors=self.colors, colorSpace='rgb', units='pix')
event_clock.reset() win.flip() # Set up memory probe screen xys = [] loop_radius = 8 n_circ = 360 for theta in np.linspace(0, 360, n_circ, endpoint=False): xys.append((loop_radius * np.cos(theta * np.pi / 180), loop_radius * np.sin(theta * np.pi / 180))) stim = visual.ElementArrayStim(win, nElements=n_circ, sizes=0.9, xys=xys, elementTex=None, elementMask="circle", colors=rgb.reshape(n_circ, 3), colorSpace='rgb', interpolate=True) mask1 = visual.Circle(win, radius=loop_radius - 0.5, units='deg') mask1.units = 'deg' mask2 = visual.Circle(win, radius=loop_radius + 0.5, units='deg') mask2.units = 'deg' while event_clock.getTime() < 0.1: pass event_clock.reset() win.flip() probe = random.sample(np.arange(0, trial.num_stimuli), 1)[0]