def setOris(self,value,operation='', log=True): """Set the orientation for each element. Should either be a single value or an Nx1 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,)]: value = value.repeat(self.nElements) elif value.shape in [(self.nElements,), (self.nElements,1)]: pass #is already Nx1 else: raise ValueError("New value for setOris should be either Nx1 or a single value") # flip orientation so, when drawn, it matches the convention of other # visual stimuli value = -value #set value setWithOperation(self, 'oris', value, operation) self.needVertexUpdate=True if log and self.autoLog: self.win.logOnFlip("Set %s oris=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def setSfs(self, value,operation='', log=True): """Set the spatial frequency for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list (spatial frequency of the element in X and Y). If the units for the stimulus are 'pix' or 'norm' then the units of sf are cycles per stimulus width. For units of 'deg' or 'cm' the units are c/cm or c/deg respectively. """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,),(2,)]: value = numpy.resize(value, [self.nElements,2]) elif value.shape in [(self.nElements,), (self.nElements,1)]: value.shape=(self.nElements,1)#set to be 2D value = value.repeat(2,1) #repeat once on dim 1 elif value.shape == (self.nElements,2): pass#all is good else: raise ValueError("New value for setSfs should be either Nx1, Nx2 or a single value") # Set value and log setWithOperation(self, 'sfs', value, operation) if log and self.autoLog: self.win.logOnFlip("Set %s sfs=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def setPhases(self,value,operation='', log=True): """Set the phase for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list (for separate X and Y phase) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,),(2,)]: value = numpy.resize(value, [self.nElements,2]) elif value.shape in [(self.nElements,), (self.nElements,1)]: value.shape=(self.nElements,1)#set to be 2D value = value.repeat(2,1) #repeat once on dim 1 elif value.shape == (self.nElements,2): pass#all is good else: raise ValueError("New value for setPhases should be either Nx1, Nx2 or a single value") #set value and log setWithOperation(self, 'phases', value, operation) self.needTexCoordUpdate=True if log and self.autoLog: self.win.logOnFlip("Set %s phases=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def setContrs(self,value,operation='', log=True): """Set the contrast for each element. Should either be: - a single value - an Nx1 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,)]: value = value.repeat(self.nElements) elif value.shape in [(self.nElements,), (self.nElements,1)]: pass #is already Nx1 else: raise ValueError("New value for setContrs should be either Nx1 or a single value") #set value and log setWithOperation(self, 'contrs', value, operation) self.needColorUpdate=True if log and self.autoLog: self.win.logOnFlip("Set %s contrs=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def _set(self, attrib, val, op='', log=True): """Use this to set attributes of your stimulus after initialising it. :Parameters: attrib : a string naming any of the attributes of the stimulus (set during init) val : the value to be used in the operation on the attrib op : a string representing the operation to be performed (optional) most maths operators apply ('+','-','*'...) examples:: myStim.set('rgb',0) #will simply set all guns to zero (black) myStim.set('rgb',0.5,'+') #will increment all 3 guns by 0.5 myStim.set('rgb',(1.0,0.5,0.5),'*') # will keep the red gun the same and halve the others """ #format the input value as float vectors if type(val) in [tuple, list]: val = numpy.array(val, float) #change the attribute as requested setWithOperation(self, attrib, val, op) #update the actual coherence for the requested coherence and nDots if attrib in ['nDots', 'coherence']: self.coherence = round(self.coherence * self.nDots) / self.nDots logAttrib(self, log, attrib)
def setSizes(self,value,operation='', log=True): """Set the size for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,),(2,)]: value = numpy.resize(value, [self.nElements,2]) elif value.shape in [(self.nElements,), (self.nElements,1)]: value.shape=(self.nElements,1)#set to be 2D value = value.repeat(2,1) #repeat once on dim 1 elif value.shape == (self.nElements,2): pass#all is good else: raise ValueError("New value for setSizes should be either Nx1, Nx2 or a single value") #set value and log setWithOperation(self, 'sizes', value, operation) self._needVertexUpdate=True self._needTexCoordUpdate=True if log and self.autoLog: self.win.logOnFlip("Set %s sizes=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def _set(self, attrib, val, op='', log=True): """Use this to set attributes of your stimulus after initialising it. :Parameters: attrib : a string naming any of the attributes of the stimulus (set during init) val : the value to be used in the operation on the attrib op : a string representing the operation to be performed (optional) most maths operators apply ('+','-','*'...) examples:: myStim.set('rgb',0) #will simply set all guns to zero (black) myStim.set('rgb',0.5,'+') #will increment all 3 guns by 0.5 myStim.set('rgb',(1.0,0.5,0.5),'*') # will keep the red gun the same and halve the others """ #format the input value as float vectors if type(val) in [tuple,list]: val=numpy.array(val,float) #change the attribute as requested setWithOperation(self, attrib, val, op) #update the actual coherence for the requested coherence and nDots if attrib in ['nDots','coherence']: self.coherence=round(self.coherence*self.nDots)/self.nDots if log and self.autoLog: self.win.logOnFlip("Set %s %s=%s" %(self.name, attrib, getattr(self,attrib)), level=logging.EXP)
def setSizes(self,value,operation='', log=True): """Set the size for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,),(2,)]: value = numpy.resize(value, [self.nElements,2]) elif value.shape in [(self.nElements,), (self.nElements,1)]: value.shape=(self.nElements,1)#set to be 2D value = value.repeat(2,1) #repeat once on dim 1 elif value.shape == (self.nElements,2): pass#all is good else: raise ValueError("New value for setSizes should be either Nx1, Nx2 or a single value") #set value and log setWithOperation(self, 'sizes', value, operation) logAttrib(self, log, 'sizes', type(value)) self._needVertexUpdate=True self._needTexCoordUpdate=True
def setSfs(self, value, operation="", log=True): """Set the spatial frequency for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list (spatial frequency of the element in X and Y). If the units for the stimulus are 'pix' or 'norm' then the units of sf are cycles per stimulus width. For units of 'deg' or 'cm' the units are c/cm or c/deg respectively. """ # make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) # check shape if value.shape in [(), (1,), (2,)]: value = numpy.resize(value, [self.nElements, 2]) elif value.shape in [(self.nElements,), (self.nElements, 1)]: value.shape = (self.nElements, 1) # set to be 2D value = value.repeat(2, 1) # repeat once on dim 1 elif value.shape == (self.nElements, 2): pass # all is good else: raise ValueError("New value for setSfs should be either Nx1, Nx2 or a single value") # Set value and log setWithOperation(self, "sfs", value, operation) logAttrib(self, log, "sfs", type(value)) self._needTexCoordUpdate = True
def _set(self, attrib, val, op='', log=True): """ Deprecated. Use methods specific to the parameter you want to set e.g. :: stim.pos = [3,2.5] stim.ori = 45 stim.phase += 0.5 NB this method does not flag the need for updates any more - that is done by specific methods as described above. """ if op == None: op = '' #format the input value as float vectors if type(val) in (tuple, list): val = numpy.array(val, float) setWithOperation(self, attrib, val, op) if log and self.autoLog: self.win.logOnFlip("Set %s %s=%s" % (self.name, attrib, getattr(self, attrib)), level=logging.EXP, obj=self)
def setSfs(self, value, operation='', log=True): """Set the spatial frequency for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list (spatial frequency of the element in X and Y). If the units for the stimulus are 'pix' or 'norm' then the units of sf are cycles per stimulus width. For units of 'deg' or 'cm' the units are c/cm or c/deg respectively. """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(), (1, ), (2, )]: value = numpy.resize(value, [self.nElements, 2]) elif value.shape in [(self.nElements, ), (self.nElements, 1)]: value.shape = (self.nElements, 1) #set to be 2D value = value.repeat(2, 1) #repeat once on dim 1 elif value.shape == (self.nElements, 2): pass #all is good else: raise ValueError( "New value for setSfs should be either Nx1, Nx2 or a single value" ) # Set value and log setWithOperation(self, 'sfs', value, operation) logAttrib(self, log, 'sfs', type(value))
def setPhases(self, value, operation='', log=True): """Set the phase for each element. Should either be: - a single value - an Nx1 array/list - an Nx2 array/list (for separate X and Y phase) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(), (1, ), (2, )]: value = numpy.resize(value, [self.nElements, 2]) elif value.shape in [(self.nElements, ), (self.nElements, 1)]: value.shape = (self.nElements, 1) #set to be 2D value = value.repeat(2, 1) #repeat once on dim 1 elif value.shape == (self.nElements, 2): pass #all is good else: raise ValueError( "New value for setPhases should be either Nx1, Nx2 or a single value" ) #set value and log setWithOperation(self, 'phases', value, operation) logAttrib(self, log, 'phases', type(value)) self._needTexCoordUpdate = True
def setContrs(self,value,operation='', log=True): """Set the contrast for each element. Should either be: - a single value - an Nx1 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,)]: value = value.repeat(self.nElements) elif value.shape in [(self.nElements,), (self.nElements,1)]: pass #is already Nx1 else: raise ValueError("New value for setContrs should be either Nx1 or a single value") #set value and log setWithOperation(self, 'contrs', value, operation) self._needColorUpdate=True if log and self.autoLog: self.win.logOnFlip("Set %s contrs=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def setXYs(self, value=None, operation='', log=True): """Set the xy values of the element centres (relative to the centre of the field). Values should be: - None - an array/list of Nx2 coordinates. If value is None then the xy positions will be generated automatically, based on the fieldSize and fieldPos. In this case opacity will also be overridden by this function (it is used to make elements outside the field invisible. """ if value == None: if self.fieldShape in ['sqr', 'square']: self.xys = numpy.random.rand( self.nElements, 2 ) * self.fieldSize - self.fieldSize / 2 #initialise a random array of X,Y #gone outside the square self.xys[:, 0] = ((self.xys[:, 0] + self.fieldSize[0] / 2) % self.fieldSize[0]) - self.fieldSize[0] / 2 self.xys[:, 1] = ((self.xys[:, 1] + self.fieldSize[1] / 2) % self.fieldSize[1]) - self.fieldSize[1] / 2 elif self.fieldShape is 'circle': #take twice as many elements as we need (and cull the ones outside the circle) xys = numpy.random.rand( self.nElements * 2, 2 ) * self.fieldSize - self.fieldSize / 2 #initialise a random array of X,Y #gone outside the square xys[:, 0] = ((xys[:, 0] + self.fieldSize[0] / 2) % self.fieldSize[0]) - self.fieldSize[0] / 2 xys[:, 1] = ((xys[:, 1] + self.fieldSize[1] / 2) % self.fieldSize[1]) - self.fieldSize[1] / 2 #use a circular envelope and flips dot to opposite edge if they fall #beyond radius. #NB always circular - uses fieldSize in X only normxy = xys / (self.fieldSize / 2.0) dotDist = numpy.sqrt((normxy[:, 0]**2.0 + normxy[:, 1]**2.0)) self.xys = xys[dotDist < 1.0, :][0:self.nElements] else: #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if not (value.shape in [(), (2, ), (self.nElements, 2)]): raise ValueError( "New value for setXYs should be either None or Nx2") #set value setWithOperation(self, 'xys', value, operation) self._needVertexUpdate = True if log and self.autoLog: self.win.logOnFlip("Set %s XYs=%s" % (self.name, type(value)), level=logging.EXP, obj=self)
def setFieldPos(self,value,operation='', log=True): """Set the centre of the array (X,Y) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape != (2,): raise ValueError("New value for setFieldPos should be [x,y]") #set value and log setWithOperation(self, 'fieldPos', value, operation) logAttrib(self, log, 'fieldPos', type(value))
def setFieldPos(self, value, operation='', log=True): """Set the centre of the array (X,Y) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape != (2, ): raise ValueError("New value for setFieldPos should be [x,y]") #set value and log setWithOperation(self, 'fieldPos', value, operation) logAttrib(self, log, 'fieldPos', type(value)) self._needVertexUpdate = True
def setFieldSize(self,value,operation='', log=True): """Set the size of the array on the screen (will override current XY positions of the elements) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape not in [(2,),(1,)]: raise ValueError("New value for setFieldSize should be [x,y] or a single value") #set value and log setWithOperation(self, 'fieldSize', value, operation) logAttrib(self, log, 'fieldSize') self.setXYs(log=False)#to reflect new settings, overriding individual xys
def setFieldPos(self,value,operation='', log=True): """Set the centre of the array (X,Y) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape != (2,): raise ValueError("New value for setFieldPos should be [x,y]") #set value and log setWithOperation(self, 'fieldPos', value, operation) if log and self.autoLog: self.win.logOnFlip("Set %s fieldPos=%s" %(self.name, type(value)), level=logging.EXP,obj=self)
def setFieldSize(self, value, operation='', log=True): """Set the size of the array on the screen (will override current XY positions of the elements) """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape not in [(2, ), (1, )]: raise ValueError( "New value for setFieldSize should be [x,y] or a single value") #set value and log setWithOperation(self, 'fieldSize', value, operation) logAttrib(self, log, 'fieldSize') self.setXYs( log=False) #to reflect new settings, overriding individual xys
def setVertices(self, value=None, operation="", log=True): """Set the xy values of the vertices (relative to the centre of the field). Values should be: - an array/list of Nx2 coordinates. """ # make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) # check shape if not (value.shape == (2,) or (len(value.shape) == 2 and value.shape[1] == 2)): raise ValueError("New value for setXYs should be 2x1 or Nx2") # set value and log setWithOperation(self, "vertices", value, operation) logAttrib(self, log, "vertices", value) self._needVertexUpdate = True
def _set(self, attrib, val, op='', log=True): """ Use this method when you want to be able to suppress logging (e.g., in tests). Typically better to use methods specific to the parameter, e.g. :: stim.pos = [3,2.5] stim.ori = 45 stim.phase += 0.5 NB this method does not flag the need for updates any more - that is done by specific methods as described above. """ if op==None: op='' #format the input value as float vectors if type(val) in [tuple, list, numpy.ndarray]: val = val2array(val) # Handle operations setWithOperation(self, attrib, val, op)
def setXYs(self, value=None, operation="", log=True): """Set the xy values of the element centres (relative to the centre of the field). Values should be: - None - an array/list of Nx2 coordinates. If value is None then the xy positions will be generated automatically, based on the fieldSize and fieldPos. In this case opacity will also be overridden by this function (it is used to make elements outside the field invisible. """ if value == None: if self.fieldShape in ["sqr", "square"]: self.xys = ( numpy.random.rand(self.nElements, 2) * self.fieldSize - self.fieldSize / 2 ) # initialise a random array of X,Y # gone outside the square self.xys[:, 0] = ((self.xys[:, 0] + self.fieldSize[0] / 2) % self.fieldSize[0]) - self.fieldSize[0] / 2 self.xys[:, 1] = ((self.xys[:, 1] + self.fieldSize[1] / 2) % self.fieldSize[1]) - self.fieldSize[1] / 2 elif self.fieldShape is "circle": # take twice as many elements as we need (and cull the ones outside the circle) xys = ( numpy.random.rand(self.nElements * 2, 2) * self.fieldSize - self.fieldSize / 2 ) # initialise a random array of X,Y # gone outside the square xys[:, 0] = ((xys[:, 0] + self.fieldSize[0] / 2) % self.fieldSize[0]) - self.fieldSize[0] / 2 xys[:, 1] = ((xys[:, 1] + self.fieldSize[1] / 2) % self.fieldSize[1]) - self.fieldSize[1] / 2 # use a circular envelope and flips dot to opposite edge if they fall # beyond radius. # NB always circular - uses fieldSize in X only normxy = xys / (self.fieldSize / 2.0) dotDist = numpy.sqrt((normxy[:, 0] ** 2.0 + normxy[:, 1] ** 2.0)) self.xys = xys[dotDist < 1.0, :][0 : self.nElements] else: # make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) # check shape if not (value.shape in [(), (2,), (self.nElements, 2)]): raise ValueError("New value for setXYs should be either None or Nx2") # set value setWithOperation(self, "xys", value, operation) self._needVertexUpdate = True logAttrib(self, log, "XYs", type(value))
def setOpacities(self,value,operation='', log=True): """Set the opacity for each element. Should either be a single value or an Nx1 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(),(1,)]: value = value.repeat(self.nElements) elif value.shape in [(self.nElements,), (self.nElements,1)]: pass #is already Nx1 else: raise ValueError("New value for setOpacities should be either Nx1 or a single value") #set value and log setWithOperation(self, 'opacities', value, operation) logAttrib(self, log, 'opacities', type(value))
def setVertices(self,value=None, operation='', log=True): """Set the xy values of the vertices (relative to the centre of the field). Values should be: - an array/list of Nx2 coordinates. """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if not (value.shape==(2,) \ or (len(value.shape)==2 and value.shape[1]==2) ): raise ValueError("New value for setXYs should be 2x1 or Nx2") #set value and log setWithOperation(self, 'vertices', value, operation) logAttrib(self, log, 'vertices', value) self._needVertexUpdate=True
def _set(self, attrib, val, op='', log=True): """ Deprecated. Use methods specific to the parameter you want to set e.g. :: stim.pos = [3,2.5] stim.ori = 45 stim.phase += 0.5 NB this method does not flag the need for updates any more - that is done by specific methods as described above. """ if op==None: op='' #format the input value as float vectors if type(val) in (tuple, list): val=numpy.array(val, float) setWithOperation(self, attrib, val, op) logAttrib(self, log, attrib)
def setOris(self, value, operation="", log=True): """Set the orientation for each element. Should either be a single value or an Nx1 array/list """ # make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) # check shape if value.shape in [(), (1,)]: value = value.repeat(self.nElements) elif value.shape in [(self.nElements,), (self.nElements, 1)]: pass # is already Nx1 else: raise ValueError("New value for setOris should be either Nx1 or a single value") # set value setWithOperation(self, "oris", value, operation) logAttrib(self, log, "oris", type(value)) self._needVertexUpdate = True
def setOpacities(self, value, operation='', log=True): """Set the opacity for each element. Should either be a single value or an Nx1 array/list """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if value.shape in [(), (1, )]: value = value.repeat(self.nElements) elif value.shape in [(self.nElements, ), (self.nElements, 1)]: pass #is already Nx1 else: raise ValueError( "New value for setOpacities should be either Nx1 or a single value" ) #set value and log setWithOperation(self, 'opacities', value, operation) logAttrib(self, log, 'opacities', type(value))
def setVertices(self,value=None, operation='', log=True): """Set the xy values of the vertices (relative to the centre of the field). Values should be: - an array/list of Nx2 coordinates. """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if not (value.shape==(2,) \ or (len(value.shape)==2 and value.shape[1]==2) ): raise ValueError("New value for setXYs should be 2x1 or Nx2") #set value and log setWithOperation(self, 'vertices', value, operation) self.needVertexUpdate=True if log and self.autoLog: self.win.logOnFlip("Set %s vertices=%s" %(self.name, value), level=logging.EXP,obj=self)
def setVertices(self, value=None, operation='', log=True): """Set the xy values of the vertices (relative to the centre of the field). Values should be: - an array/list of Nx2 coordinates. """ #make into an array if type(value) in [int, float, list, tuple]: value = numpy.array(value, dtype=float) #check shape if not (value.shape==(2,) \ or (len(value.shape)==2 and value.shape[1]==2) ): raise ValueError("New value for setXYs should be 2x1 or Nx2") #set value and log setWithOperation(self, 'vertices', value, operation) self._needVertexUpdate = True if log and self.autoLog: self.win.logOnFlip("Set %s vertices=%s" % (self.name, value), level=logging.EXP, obj=self)
def _set(self, attrib, val, op='', log=True): """ Deprecated. Use methods specific to the parameter you want to set e.g. :: stim.pos = [3,2.5] stim.ori = 45 stim.phase += 0.5 NB this method does not flag the need for updates any more - that is done by specific methods as described above. """ if op==None: op='' #format the input value as float vectors if type(val) in (tuple, list): val=numpy.array(val, float) setWithOperation(self, attrib, val, op) if log and self.autoLog: self.win.logOnFlip("Set %s %s=%s" %(self.name, attrib, getattr(self,attrib)), level=logging.EXP,obj=self)
def setVertices(self, value=None, operation='', log=True): """Usually you can use 'stim.attribute = value' syntax instead, but use this method if you need to suppress the log message """ setWithOperation(self, 'vertices', value, operation, autoLog=log)
def setColor(obj, color, colorSpace=None, operation='', rgbAttrib='rgb', #or 'fillRGB' etc colorAttrib='color', #or 'fillColor' etc colorSpaceAttrib=None, #e.g. 'colorSpace' or 'fillColorSpace' log=True): """Provides the workings needed by setColor, and can perform this for any arbitrary color type (e.g. fillColor,lineColor etc) """ #how this works: #rather than using obj.rgb=rgb this function uses setattr(obj,'rgb',rgb) #color represents the color in the native space #colorAttrib is the name that color will be assigned using setattr(obj,colorAttrib,color) #rgb is calculated from converting color #rgbAttrib is the attribute name that rgb is stored under, e.g. lineRGB for obj.lineRGB #colorSpace and takes name from colorAttrib+space e.g. obj.lineRGBSpace=colorSpace if colorSpaceAttrib==None: colorSpaceAttrib = colorAttrib+'Space' # Handle strings and returns immediately as operations, colorspace etc. does not apply here. if type(color) in [str, unicode, numpy.string_]: if color.lower() in colors.colors255.keys(): #set rgb, color and colorSpace setattr(obj,rgbAttrib,numpy.array(colors.colors255[color.lower()], float)) obj.__dict__[colorSpaceAttrib] = 'named' #e.g. 3rSpace='named' obj.__dict__[colorAttrib] = color #e.g. obj.color='red' setTexIfNoShaders(obj) return elif color[0]=='#' or color[0:2]=='0x': setattr(obj,rgbAttrib,numpy.array(colors.hex2rgb255(color)))#e.g. obj.rgb=[0,0,0] obj.__dict__[colorSpaceAttrib] = 'hex' #e.g. obj.colorSpace='hex' obj.__dict__[colorAttrib] = color #e.g. Qr='#000000' setTexIfNoShaders(obj) return #we got a string, but it isn't in the list of named colors and doesn't work as a hex else: raise AttributeError("PsychoPy can't interpret the color string '%s'" %color) # If it wasn't a strin, do check and conversion of scalars, sequences and other stuff. else: color = val2array(color, length=3) if color==None: setattr(obj,rgbAttrib,None)#e.g. obj.rgb=[0,0,0] obj.__dict__[colorSpaceAttrib] = None #e.g. obj.colorSpace='hex' obj.__dict__[colorAttrib] = None #e.g. obj.color='#000000' setTexIfNoShaders(obj) #at this point we have a numpy array of 3 vals (actually we haven't checked that there are 3) #check if colorSpace is given and use obj.colorSpace if not if colorSpace==None: colorSpace=getattr(obj,colorSpaceAttrib) #using previous color space - if we got this far in the _stColor function #then we haven't been given a color name - we don't know what color space to use. if colorSpace == 'named': logging.error("If you setColor with a numeric color value then you need to specify a color space, e.g. setColor([1,1,-1],'rgb'), unless you used a numeric value previously in which case PsychoPy will reuse that color space.)") return #check whether combining sensible colorSpaces (e.g. can't add things to hex or named colors) if operation!='' and getattr(obj,colorSpaceAttrib) in ['named','hex']: raise AttributeError("setColor() cannot combine ('%s') colors within 'named' or 'hex' color spaces"\ %(operation)) elif operation!='' and colorSpace!=getattr(obj,colorSpaceAttrib) : raise AttributeError("setColor cannot combine ('%s') colors from different colorSpaces (%s,%s)"\ %(operation, obj.colorSpace, colorSpace)) else:#OK to update current color setWithOperation(obj, colorAttrib, color, operation, True) #get window (for color conversions) if colorSpace in ['dkl','lms']: #only needed for these spaces if hasattr(obj,'dkl_rgb'): win=obj #obj is probably a Window elif hasattr(obj, 'win'): win=obj.win #obj is probably a Stimulus else: win=None logging.error("_setColor() is being applied to something that has no known Window object") #convert new obj.color to rgb space newColor=getattr(obj, colorAttrib) if colorSpace in ['rgb','rgb255']: setattr(obj,rgbAttrib, newColor) elif colorSpace=='dkl': if numpy.all(win.dkl_rgb==numpy.ones([3,3])): dkl_rgb=None else: dkl_rgb=win.dkl_rgb setattr(obj,rgbAttrib, colors.dkl2rgb(numpy.asarray(newColor).transpose(), dkl_rgb) ) elif colorSpace=='lms': if numpy.all(win.lms_rgb==numpy.ones([3,3])): lms_rgb=None elif win.monitor.getPsychopyVersion()<'1.76.00': logging.error("The LMS calibration for this monitor was carried out before version 1.76.00." +\ " We would STRONGLY recommend that you repeat the color calibration before using this color space (contact Jon for further info)") lms_rgb=win.lms_rgb else: lms_rgb=win.lms_rgb setattr(obj,rgbAttrib, colors.lms2rgb(newColor, lms_rgb) ) elif colorSpace=='hsv': setattr(obj,rgbAttrib, colors.hsv2rgb(numpy.asarray(newColor)) ) else: logging.error('Unknown colorSpace: %s' %colorSpace) obj.__dict__[colorSpaceAttrib] = colorSpace #store name of colorSpace for future ref and for drawing #if needed, set the texture too setTexIfNoShaders(obj) if hasattr(obj, 'autoLog'): autoLog = obj.autoLog else: autoLog = False if autoLog and log: if hasattr(obj,'win'): obj.win.logOnFlip("Set %s.%s=%s (%s)" %(obj.name,colorAttrib,newColor,colorSpace), level=logging.EXP,obj=obj) else: obj.logOnFlip("Set Window %s=%s (%s)" %(colorAttrib,newColor,colorSpace), level=logging.EXP,obj=obj)
def setColor( obj, color, colorSpace=None, operation='', rgbAttrib='rgb', #or 'fillRGB' etc colorAttrib='color', #or 'fillColor' etc colorSpaceAttrib=None, #e.g. 'colorSpace' or 'fillColorSpace' log=True): """Provides the workings needed by setColor, and can perform this for any arbitrary color type (e.g. fillColor,lineColor etc) """ #how this works: #rather than using obj.rgb=rgb this function uses setattr(obj,'rgb',rgb) #color represents the color in the native space #colorAttrib is the name that color will be assigned using setattr(obj,colorAttrib,color) #rgb is calculated from converting color #rgbAttrib is the attribute name that rgb is stored under, e.g. lineRGB for obj.lineRGB #colorSpace and takes name from colorAttrib+space e.g. obj.lineRGBSpace=colorSpace if colorSpaceAttrib == None: colorSpaceAttrib = colorAttrib + 'Space' # Handle strings and returns immediately as operations, colorspace etc. does not apply here. if type(color) in [str, unicode, numpy.string_]: if color.lower() in colors.colors255.keys(): #set rgb, color and colorSpace setattr(obj, rgbAttrib, numpy.array(colors.colors255[color.lower()], float)) obj.__dict__[colorSpaceAttrib] = 'named' #e.g. 3rSpace='named' obj.__dict__[colorAttrib] = color #e.g. obj.color='red' setTexIfNoShaders(obj) return elif color[0] == '#' or color[0:2] == '0x': setattr(obj, rgbAttrib, numpy.array( colors.hex2rgb255(color))) #e.g. obj.rgb=[0,0,0] obj.__dict__[colorSpaceAttrib] = 'hex' #e.g. obj.colorSpace='hex' obj.__dict__[colorAttrib] = color #e.g. Qr='#000000' setTexIfNoShaders(obj) return #we got a string, but it isn't in the list of named colors and doesn't work as a hex else: raise AttributeError( "PsychoPy can't interpret the color string '%s'" % color) # If it wasn't a strin, do check and conversion of scalars, sequences and other stuff. else: color = val2array(color, length=3) if color == None: setattr(obj, rgbAttrib, None) #e.g. obj.rgb=[0,0,0] obj.__dict__[colorSpaceAttrib] = None #e.g. obj.colorSpace='hex' obj.__dict__[colorAttrib] = None #e.g. obj.color='#000000' setTexIfNoShaders(obj) #at this point we have a numpy array of 3 vals (actually we haven't checked that there are 3) #check if colorSpace is given and use obj.colorSpace if not if colorSpace == None: colorSpace = getattr(obj, colorSpaceAttrib) #using previous color space - if we got this far in the _stColor function #then we haven't been given a color name - we don't know what color space to use. if colorSpace == 'named': logging.error( "If you setColor with a numeric color value then you need to specify a color space, e.g. setColor([1,1,-1],'rgb'), unless you used a numeric value previously in which case PsychoPy will reuse that color space.)" ) return #check whether combining sensible colorSpaces (e.g. can't add things to hex or named colors) if operation != '' and getattr(obj, colorSpaceAttrib) in ['named', 'hex']: raise AttributeError("setColor() cannot combine ('%s') colors within 'named' or 'hex' color spaces"\ %(operation)) elif operation != '' and colorSpace != getattr(obj, colorSpaceAttrib): raise AttributeError("setColor cannot combine ('%s') colors from different colorSpaces (%s,%s)"\ %(operation, obj.colorSpace, colorSpace)) else: #OK to update current color setWithOperation(obj, colorAttrib, color, operation, True) #get window (for color conversions) if colorSpace in ['dkl', 'lms']: #only needed for these spaces if hasattr(obj, 'dkl_rgb'): win = obj #obj is probably a Window elif hasattr(obj, 'win'): win = obj.win #obj is probably a Stimulus else: win = None logging.error( "_setColor() is being applied to something that has no known Window object" ) #convert new obj.color to rgb space newColor = getattr(obj, colorAttrib) if colorSpace in ['rgb', 'rgb255']: setattr(obj, rgbAttrib, newColor) elif colorSpace == 'dkl': if numpy.all(win.dkl_rgb == numpy.ones([3, 3])): dkl_rgb = None else: dkl_rgb = win.dkl_rgb setattr(obj, rgbAttrib, colors.dkl2rgb(numpy.asarray(newColor).transpose(), dkl_rgb)) elif colorSpace == 'lms': if numpy.all(win.lms_rgb == numpy.ones([3, 3])): lms_rgb = None elif win.monitor.getPsychopyVersion() < '1.76.00': logging.error("The LMS calibration for this monitor was carried out before version 1.76.00." +\ " We would STRONGLY recommend that you repeat the color calibration before using this color space (contact Jon for further info)") lms_rgb = win.lms_rgb else: lms_rgb = win.lms_rgb setattr(obj, rgbAttrib, colors.lms2rgb(newColor, lms_rgb)) elif colorSpace == 'hsv': setattr(obj, rgbAttrib, colors.hsv2rgb(numpy.asarray(newColor))) else: logging.error('Unknown colorSpace: %s' % colorSpace) obj.__dict__[ colorSpaceAttrib] = colorSpace #store name of colorSpace for future ref and for drawing #if needed, set the texture too setTexIfNoShaders(obj) if hasattr(obj, 'autoLog'): autoLog = obj.autoLog else: autoLog = False if autoLog and log: if hasattr(obj, 'win'): obj.win.logOnFlip("Set %s.%s=%s (%s)" % (obj.name, colorAttrib, newColor, colorSpace), level=logging.EXP, obj=obj) else: obj.logOnFlip("Set Window %s=%s (%s)" % (colorAttrib, newColor, colorSpace), level=logging.EXP, obj=obj)
def setFieldCoherence(self, val, op="", log=True): """Usually you can use 'stim.attribute = value' syntax instead, but use this method if you need to suppress the log message """ setWithOperation(self, "coherence", val, op, autoLog=log) # calls attributeSetter
def setSpeed(self, val, op="", log=True): """Usually you can use 'stim.attribute = value' syntax instead, but use this method if you need to suppress the log message """ setWithOperation(self, "speed", val, op, autoLog=log)
def setRadialPhase(self, value, operation='', log=True): """Usually you can use 'stim.attribute = value' syntax instead, but use this method if you need to suppress the log message """ setWithOperation(self, 'radialPhase', value, operation, autoLog=log) # calls the attributeSetter