def sf(self, value): """ :ref:`x,y-pair <attrib-xy>` or :ref:`scalar <attrib-scalar>` Where `units` == 'deg' or 'cm' units are in cycles per deg/cm. If `units` == 'norm' then sf units are in cycles per stimulus (so scale with stimulus size). If texture is an image loaded from a file then sf defaults to 1/stim size to give one cycle of the image. Spatial frequency. """ # Recode phase to numpy array if value == None: """Set the sf to default (e.g. to the 1.0/size of the loaded image etc)""" if self.units in ['pix', 'pixels'] \ or self._origSize is not None and self.units in ['deg', 'cm']: value = 1.0 / self.size #default to one cycle else: value = numpy.array([1.0, 1.0]) else: value = val2array(value) # Set value and update stuff self.__dict__['sf'] = value self._calcCyclesPerStim() self._needUpdate = True
def fieldPos(self, value): """:ref:`x,y-pair <attrib-xy>`. Set the centre of the array of elements. :ref:`Operations <attrib-operations>` are supported.""" self.__dict__['fieldPos'] = val2array(value, False, False) self._needVertexUpdate = True
def sf(self, value): """Spatial frequency of the grating texture Should be a :ref:`x,y-pair <attrib-xy>` or :ref:`scalar <attrib-scalar>` or None. If `units` == 'deg' or 'cm' units are in cycles per deg or cm as appropriate. If `units` == 'norm' then sf units are in cycles per stimulus (and so SF scales with stimulus size). If texture is an image loaded from a file then sf=None defaults to 1/stimSize to give one cycle of the image. """ # Recode phase to numpy array if value is None: # Set the sf to default (e.g. to the 1.0/size of the loaded image if (self.units in ('pix', 'pixels') or self._origSize is not None and self.units in ('deg', 'cm')): value = 1.0 / self.size # default to one cycle else: value = numpy.array([1.0, 1.0]) else: value = val2array(value) # Set value and update stuff self.__dict__['sf'] = value self._calcCyclesPerStim() self._needUpdate = True
def envsf(self, value): """Spatial frequency of the envelope texture Should be a :ref:`x,y-pair <attrib-xy>` or :ref:`scalar <attrib-scalar>` or None. If `units` == 'deg' or 'cm' units are in cycles per deg or cm as appropriate. If `units` == 'norm' then sf units are in cycles per stimulus (and so envsf scales with stimulus size). If texture is an image loaded from a file then envsf=None defaults to 1/stimSize to give one cycle of the image. Note sf is inhertited from GratingStim and controls the spatial frequency of the carrier """ # Recode phase to numpy array if value is None: # set the sf to default e.g. 1./size of the loaded image etc if (self.units in ['pix', 'pixels'] or self._origSize is not None and self.units in ['deg', 'cm']): value = 1.0/self.size # default to one cycle else: value = numpy.array([1.0, 1.0]) else: value = val2array(value) # Set value and update stuff self.__dict__['envsf'] = value self._calcEnvCyclesPerStim() self._needUpdate = True
def size(self, value): """ :ref:`x,y-pair <attrib-xy>`, :ref:`scalar <attrib-scalar>` or None (resets to default). Supports :ref:`operations <attrib-operations>`. Units are inherited from the stimulus. Sizes can be negative and can extend beyond the window. Example:: stim.size = 0.8 # Set size to (xsize, ysize) = (0.8, 0.8), quadratic. print stim.size # Outputs array([0.8, 0.8]) stim.size += (0,5, -0.5) # make wider and flatter. Is now (1.3, 0.3) Tip: if you can see the actual pixel range this corresponds to by looking at stim._sizeRendered """ value = val2array(value) # Check correct user input self._requestedSize = value #to track whether we're just using a default # None --> set to default if value == None: """Set the size to default (e.g. to the size of the loaded image etc)""" #calculate new size if self._origSize is None: #not an image from a file value = numpy.array([0.5, 0.5]) #this was PsychoPy's original default else: #we have an image - calculate the size in `units` that matches original pixel size if self.units == 'pix': value = numpy.array(self._origSize) elif self.units == 'deg': value = pix2deg(numpy.array(self._origSize, float), self.win.monitor) elif self.units == 'cm': value = pix2cm(numpy.array(self._origSize, float), self.win.monitor) elif self.units == 'norm': value = 2 * numpy.array(self._origSize, float) / self.win.size elif self.units == 'height': value = numpy.array(self._origSize, float) / self.win.size[1] self.__dict__['size'] = value self._calcSizeRendered() if hasattr(self, '_calcCyclesPerStim'): self._calcCyclesPerStim() self._needUpdate = True
def fieldSize(self, value): """Scalar or :ref:`x,y-pair <attrib-xy>`. The size of the array of elements. This will be overridden by setting explicit xy positions for the elements. :ref:`Operations <attrib-operations>` are supported.""" self.__dict__['fieldSize'] = val2array(value, False) self.setXYs(log=False) # to reflect new settings, overriding individual xys
def pos(self, value): """:ref:`x,y-pair <attrib-xy>` specifying the he centre of the image relative to the window center. Stimuli can be positioned off-screen, beyond the window! :ref:`operations <attrib-operations>` are supported.""" self.__dict__['pos'] = val2array(value, withNone=False) self._calcPosRendered()
def vertices(self, newVerts): """A list of lists or a numpy array (Nx2) specifying xy positions of each vertex, relative to the center of the field. Assigning to vertices can be slow if there are many vertices. :ref:`Operations <attrib-operations>` supported with `.setVertices()`. """ # Check shape self.__dict__['vertices'] = val2array(newVerts, withNone=True, withScalar=True, length=2) self._needVertexUpdate = True self._tesselate(self.vertices)
def phase(self, value): """Phase of the stimulus in each dimension of the texture. Should be an :ref:`x,y-pair <attrib-xy>` or :ref:`scalar <attrib-scalar>` **NB** phase has modulus 1 (rather than 360 or 2*pi) This is a little unconventional but has the nice effect that setting phase=t*n drifts a stimulus at n Hz """ # Recode phase to numpy array value = val2array(value) self.__dict__['phase'] = value self._needUpdate = True
def envphase(self, value): """Phase of the modulation in each dimension of the envelope texture. Should be an :ref:`x,y-pair <attrib-xy>` or :ref:`scalar <attrib-scalar>` **NB** phase has modulus 1 (rather than 360 or 2*pi) This is a little unconventional but has the nice effect that setting phase=t*n drifts a stimulus at n Hz Note phase in inherited from GratingStim and controls the phase of the carrier """ # Recode phase to numpy array value = val2array(value) self.__dict__['envphase'] = value self._needUpdate = True
def pos(self, value): """The position of the center of the stimulus in the stimulus :ref:`units <units>` Value should be an :ref:`x,y-pair <attrib-xy>`. :ref:`Operations <attrib-operations>` are also supported. Example:: stim.pos = (0.5, 0) # Set slightly to the right of center stim.pos += (0.5, -1) # Increment pos rightwards and upwards. Is now (1.0, -1.0) stim.pos *= 0.2 # Move stim towards the center. Is now (0.2, -0.2) Tip: if you can see the actual pixel range this corresponds to by looking at `stim._posRendered` """ self.__dict__['pos'] = val2array(value, False, False) self._calcPosRendered()
def size(self, value): """The size (w,h) of the stimulus in the stimulus :ref:`units <units>` Value should be :ref:`x,y-pair <attrib-xy>`, :ref:`scalar <attrib-scalar>` (applies to both dimensions) or None (resets to default). :ref:`Operations <attrib-operations>` are supported. Sizes can be negative (causing a mirror-image reversal) and can extend beyond the window. Example:: stim.size = 0.8 # Set size to (xsize, ysize) = (0.8, 0.8), quadratic. print stim.size # Outputs array([0.8, 0.8]) stim.size += (0.5, -0.5) # make wider and flatter. Is now (1.3, 0.3) Tip: if you can see the actual pixel range this corresponds to by looking at `stim._sizeRendered` """ value = val2array(value) # Check correct user input self._requestedSize = value #to track whether we're just using a default # None --> set to default if value == None: """Set the size to default (e.g. to the size of the loaded image etc)""" #calculate new size if self._origSize is None: #not an image from a file value = numpy.array([0.5, 0.5]) #this was PsychoPy's original default else: #we have an image - calculate the size in `units` that matches original pixel size if self.units == 'pix': value = numpy.array(self._origSize) elif self.units in ['deg', 'degFlatPos', 'degFlat']: #NB when no size has been set (assume to use orig size in pix) this should not #be corrected for flat anyway, so degFlat==degFlatPos value = pix2deg(numpy.array(self._origSize, float), self.win.monitor) elif self.units == 'norm': value = 2 * numpy.array(self._origSize, float) / self.win.size elif self.units == 'height': value = numpy.array(self._origSize, float) / self.win.size[1] elif self.units == 'cm': value = pix2cm(numpy.array(self._origSize, float), self.win.monitor) else: raise AttributeError, "Failed to create default size for ImageStim. Unsupported unit, %s" %(repr(self.units)) self.__dict__['size'] = value self._needVertexUpdate=True self._needUpdate = True if hasattr(self, '_calcCyclesPerStim'): self._calcCyclesPerStim()
def pos(self, value): """ :ref:`x,y-pair <attrib-xy>`. :ref:`operations <attrib-operations>` supported. Set the stimulus position in the `units` inherited from the stimulus. Either list [x, y], tuple (x, y) or numpy.ndarray ([x, y]) with two elements. Example:: stim.pos = (0.5, 0) # Slightly to the right stim.pos += (0.5, -1) # Move right and up. Is now (1.0, -1.0) stim.pos *= 0.2 # Move towards the center. Is now (0.2, -0.2) Tip: if you can see the actual pixel range this corresponds to by looking at stim._posRendered """ self.__dict__['pos'] = val2array(value, False, False) self._calcPosRendered()
def vertices(self, newVerts): """A list of lists or a numpy array (Nx2) specifying xy positions of each vertex, relative to the center of the field. Assigning to vertices can be slow if there are many vertices. :ref:`Operations <attrib-operations>` supported with `.setVertices()`. """ # check if this is a name of one of our known shapes if isinstance(newVerts, basestring) and newVerts in knownShapes: newVerts = knownShapes[newVerts] # Check shape self.__dict__['vertices'] = val2array(newVerts, withNone=True, withScalar=True, length=2) self._needVertexUpdate = True self._tesselate(self.vertices)
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 pos(self, value): """The position of the center of the stimulus in the stimulus :ref:`units <units>` `value` should be an :ref:`x,y-pair <attrib-xy>`. :ref:`Operations <attrib-operations>` are also supported. Example:: stim.pos = (0.5, 0) # Set slightly to the right of center stim.pos += (0.5, -1) # Increment pos rightwards and upwards. Is now (1.0, -1.0) stim.pos *= 0.2 # Move stim towards the center. Is now (0.2, -0.2) Tip: If you need the position of stim in pixels, you can obtain it like this: from psychopy.tools.monitorunittools import posToPix posPix = posToPix(stim) """ self.__dict__['pos'] = val2array(value, False, False) self._needVertexUpdate=True self._needUpdate = 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, numpy.ndarray]: val = val2array(val) # Handle operations setWithOperation(self, attrib, val, op) logAttrib(self, log, attrib)
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, numpy.ndarray]: val = val2array(val) # Handle operations 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 __init__(self, win, image=None, mask=None, units="", pos=(0.0, 0.0), size=None, ori=0.0, color=(1.0, 1.0, 1.0), colorSpace='rgb', contrast=1.0, opacity=1.0, depth=0, interpolate=False, flipHoriz=False, flipVert=False, texRes=128, name=None, autoLog=None, maskParams=None): """ """ # Empty docstring. All doc is in attributes # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = dir() self._initParams.remove('self') super(ImageStim, self).__init__(win, units=units, name=name, autoLog=False) # set at end of init # use shaders if available by default, this is a good thing self.__dict__['useShaders'] = win._haveShaders # initialise textures for stimulus self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.__dict__['maskParams'] = maskParams self.__dict__['mask'] = mask # Not pretty (redefined later) but it works! self.__dict__['texRes'] = texRes # Other stuff self._imName = image self.isLumImage = None self.interpolate = interpolate self.flipHoriz = flipHoriz self.flipVert = flipVert self._requestedSize = size self._origSize = None # updated if an image texture gets loaded self.size = val2array(size) self.pos = numpy.array(pos, float) self.ori = float(ori) self.depth = depth # color and contrast etc self.contrast = float(contrast) self.opacity = float(opacity) self.__dict__['colorSpace'] = colorSpace # omit decorator self.setColor(color, colorSpace=colorSpace, log=False) # does an rgb pedestal make sense for an image? self.rgbPedestal = [0, 0, 0] # Set the image and mask- self.setImage(image, log=False) self.texRes = texRes # rebuilds the mask # generate a displaylist ID self._listID = GL.glGenLists(1) self._updateList() # ie refresh display list # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def __init__(self, win, filename = "", units = 'pix', size = None, pos =(0.0,0.0), ori =0.0, flipVert = False, flipHoriz = False, color=(1.0,1.0,1.0), colorSpace='rgb', opacity=1.0, name='', loop=False, autoLog=True, depth=0.0,): """ :Parameters: filename : a string giving the relative or absolute path to the movie. Can be any movie that AVbin can read (e.g. mpeg, DivX) flipVert : True or *False* If True then the movie will be top-bottom flipped flipHoriz : True or *False* If True then the movie will be right-left flipped loop : bool, optional Whether to start the movie over from the beginning if draw is called and the movie is done. """ BaseVisualStim.__init__(self, win, units=units, name=name, autoLog=autoLog) if not havePygletMedia: raise ImportError, """pyglet.media is needed for MovieStim and could not be imported. This can occur for various reasons; - psychopy.visual was imported too late (after a lib that uses scipy) - no audio output is enabled (no audio card or no speakers attached) - avbin is not installed """ self._movie=None # the actual pyglet media object self._player=pyglet.media.ManagedSoundPlayer() self._player._on_eos=self._onEos self.filename=filename self.duration=None self.loop = loop if loop and pyglet.version>='1.2': logging.error("looping of movies is not currently supported for pyglet>=1.2 only for version 1.1.4") self.loadMovie( self.filename ) self.format=self._movie.video_format self.pos = numpy.asarray(pos, float) self.depth=depth self.flipVert = flipVert self.flipHoriz = flipHoriz self.colorSpace=colorSpace self.setColor(color, colorSpace=colorSpace, log=False) self.opacity = float(opacity) self.status=NOT_STARTED #size if size == None: self.size= numpy.array([self.format.width, self.format.height] , float) else: self.size = val2array(size) self.ori = ori self._calcPosRendered() self._calcSizeRendered() # enable self.contains(), overlaps(); currently win must have pix units: self._calcVertices() #check for pyglet if win.winType!='pyglet': logging.Error('Movie stimuli can only be used with a pyglet window') core.quit()
def __init__( self, win, filename="", units='pix', size=None, pos=(0.0, 0.0), ori=0.0, flipVert=False, flipHoriz=False, color=(1.0, 1.0, 1.0), colorSpace='rgb', opacity=1.0, volume=1.0, name=None, loop=False, autoLog=None, depth=0.0, ): """ :Parameters: filename : a string giving the relative or absolute path to the movie. Can be any movie that AVbin can read (e.g. mpeg, DivX) flipVert : True or *False* If True then the movie will be top-bottom flipped flipHoriz : True or *False* If True then the movie will be right-left flipped volume : The nominal level is 1.0, and 0.0 is silence, see pyglet.media.Player loop : bool, optional Whether to start the movie over from the beginning if draw is called and the movie is done. """ # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = dir() self._initParams.remove('self') super(MovieStim, self).__init__(win, units=units, name=name, autoLog=False) self._verticesBase *= numpy.array([[-1, 1]]) # unflip if not havePygletMedia: msg = ("pyglet.media is needed for MovieStim and could not be" " imported.\nThis can occur for various reasons;" " - psychopy.visual was imported too late (after a lib" " that uses scipy)" " - no audio output is enabled (no audio card or no " "speakers attached)" " - avbin is not installed") raise ImportError(msg) self._movie = None # the actual pyglet media object self._player = pyglet.media.ManagedSoundPlayer() self._player.volume = volume try: self._player_default_on_eos = self._player.on_eos except Exception: # pyglet 1.1.4? self._player_default_on_eos = self._player._on_eos self.filename = pathToString(filename) self.duration = None self.loop = loop if loop and pyglet.version >= '1.2': logging.error("looping of movies is not currently supported " "for pyglet >= 1.2 (only for version 1.1.4)") self.loadMovie(self.filename) self.format = self._movie.video_format self.pos = numpy.asarray(pos, float) self.depth = depth self.flipVert = flipVert self.flipHoriz = flipHoriz self.opacity = float(opacity) self.status = NOT_STARTED # size if size is None: self.size = numpy.array([self.format.width, self.format.height], float) else: self.size = val2array(size) self.ori = ori self._updateVertices() if win.winType != 'pyglet': logging.error('Movie stimuli can only be used with a ' 'pyglet window') core.quit() # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def __init__(self, win, carrier="noise", mask="none", envelope="sin", units="", pos=(0.0, 0.0), size=None, sf=None, envsf=None, ori=0.0, envori=0.0, phase=(0.0, 0.0), envphase=(0.0, 0.0), beat=False, texRes=128, rgb=None, dkl=None, lms=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', contrast=0.5, # see doc moddepth=1.0, # modulation depth for envelope # not sure what this will do with an envelope stimulus. opacity=1.0, depth=0, rgbPedestal=(0.0, 0.0, 0.0), interpolate=False, name=None, autoLog=None, autoDraw=False, maskParams=None): """ """ # Empty docstring. All doc is in attributes # what local vars are defined (these are the init params) for use by # __repr__ assert win._haveShaders is True, ("Currently EnvelopeGratings need " "your graphics card to have shaders" " and yours does not seem to.") self._initParams = dir() for unecess in ['self', 'rgb', 'dkl', 'lms']: self._initParams.remove(unecess) # initialise parent class GratingStim.__init__(self, win, units=units, pos=pos, size=size, sf=sf, ori=ori, phase=phase, color=color, colorSpace=colorSpace, contrast=contrast, opacity=opacity, depth=depth, interpolate=interpolate, name=name, autoLog=autoLog, autoDraw=autoDraw, maskParams=None) # use shaders if available by default, this is a good thing self.__dict__['useShaders'] = win._haveShaders # UGLY HACK: Some parameters depend on each other for processing. # They are set "superficially" here. # TO DO: postpone calls to _createTexture, setColor and # _calcCyclesPerStim whin initiating stimulus self.__dict__['carrier'] = carrier self.__dict__['envelope'] = envelope self.__dict__['maskParams'] = maskParams # initialise textures and masks for stimulus self._carrierID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._carrierID)) self._envelopeID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._envelopeID)) self.interpolate = interpolate del self._texID # created by GratingStim.__init__ self.mask = mask self.envelope = envelope self.carrier = carrier self.envsf = val2array(envsf) self.envphase = val2array(envphase, False) self.envori = float(envori) self.moddepth = float(moddepth) self.beat = bool(beat) # print(self.CMphase) self._shaderProg = _shaders.compileProgram( _shaders.vertSimple, carrierEnvelopeMaskFrag) self.local = numpy.ones((texRes, texRes), dtype=numpy.ubyte) self.local_p = self.local.ctypes # self.local=GL.GL_UNSIGNED_BYTE(self.local) # fix scaling to window coords # self._calcCyclesPerStim() self._calcEnvCyclesPerStim() del self.__dict__['tex']
def __init__(self, win, image =None, mask =None, units ="", pos =(0.0,0.0), size =None, ori =0.0, color=(1.0,1.0,1.0), colorSpace='rgb', contrast=1.0, opacity=1.0, depth=0, interpolate=False, flipHoriz=False, flipVert=False, texRes=128, name='', autoLog=True, maskParams=None): """ :Parameters: image : The image file to be presented (most formats supported) mask : The alpha mask that can be used to control the outer shape of the stimulus + **None**, 'circle', 'gauss', 'raisedCos' + or the name of an image file (most formats supported) + or a numpy array (1xN or NxN) ranging -1:1 texRes: Sets the resolution of the mask (this is independent of the image resolution) maskParams: Various types of input. Default to None. This is used to pass additional parameters to the mask if those are needed. - For the 'raisedCos' mask, pass a dict: {'fringeWidth':0.2}, where 'fringeWidth' is a parameter (float, 0-1), determining the proportion of the patch that will be blurred by the raised cosine edge. """ BaseVisualStim.__init__(self, win, units=units, name=name, autoLog=autoLog) self.useShaders = win._haveShaders #use shaders if available by default, this is a good thing #initialise textures for stimulus self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.maskParams= maskParams self.texRes=texRes # Other stuff self._imName = image self.isLumImage = None self.interpolate=interpolate self.flipHoriz = flipHoriz self.flipVert = flipVert self._requestedSize=size self._origSize=None#if an image texture is loaded this will be updated self.size = val2array(size) self.pos = numpy.array(pos,float) self.ori = float(ori) self.depth=depth #color and contrast etc self.contrast = float(contrast) self.opacity = float(opacity) self.__dict__['colorSpace'] = colorSpace #omit decorator self.setColor(color, colorSpace=colorSpace, log=False) self.rgbPedestal=[0,0,0]#does an rgb pedestal make sense for an image? # Set the image and mask self.setImage(image, log=False) self.setMask(mask, log=False) #fix scaling to window coords self._calcSizeRendered() self._calcPosRendered() # _verticesRendered for .contains() and .overlaps() v = [(-.5,-.5), (-.5,.5), (.5,.5), (.5,-.5)] self._verticesRendered = numpy.array(self._sizeRendered, dtype=float) * v #generate a displaylist ID self._listID = GL.glGenLists(1) self._updateList()#ie refresh display list
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). OBS: log argument is deprecated - has no effect now. Logging should be done when setColor() is called. """ # 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 is None: colorSpaceAttrib = colorAttrib + 'Space' # Handle strings and returns immediately as operations, colorspace etc. # does not apply here. if isinstance(color, basestring): if operation not in ('', None): raise TypeError('Cannot do operations on named or hex color') if color.lower() in colors.colors255: # set rgb, color and colorSpace setattr(obj, rgbAttrib, np.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': # e.g. obj.rgb=[0,0,0] setattr(obj, rgbAttrib, np.array(colors.hex2rgb255(color))) obj.__dict__[colorSpaceAttrib] = 'hex' # eg obj.colorSpace='hex' obj.__dict__[colorAttrib] = color # eg Qr='#000000' setTexIfNoShaders(obj) return else: # we got a string, but it isn't in the list of named colors and # doesn't work as a hex raise AttributeError( "PsychoPy can't interpret the color string '%s'" % color) else: # If it wasn't a string, do check and conversion of scalars, # sequences and other stuff. color = val2array(color, length=3) # enforces length 1 or 3 if color is 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 # check if colorSpace is given and use obj.colorSpace if not if colorSpace is 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 in ('named', 'hex'): 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']: msg = ("setColor() cannot combine ('%s') colors " "within 'named' or 'hex' color spaces") raise AttributeError(msg % operation) elif operation != '' and colorSpace != getattr(obj, colorSpaceAttrib): msg = ("setColor cannot combine ('%s') colors" " from different colorSpaces (%s,%s)") raise AttributeError(msg % (operation, obj.colorSpace, colorSpace)) else: # OK to update current color if colorSpace == 'named': # operations don't make sense for named obj.__dict__[colorAttrib] = color else: setAttribute(obj, colorAttrib, color, log=False, operation=operation, stealth=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 (win.dkl_rgb is None or np.all(win.dkl_rgb == np.ones([3, 3]))): dkl_rgb = None else: dkl_rgb = win.dkl_rgb setattr(obj, rgbAttrib, colors.dkl2rgb( np.asarray(newColor).transpose(), dkl_rgb)) elif colorSpace == 'lms': if (win.lms_rgb is None or np.all(win.lms_rgb == np.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(np.asarray(newColor))) elif colorSpace is None: pass # probably using named colors? else: logging.error('Unknown colorSpace: %s' % colorSpace) # store name of colorSpace for future ref and for drawing obj.__dict__[colorSpaceAttrib] = colorSpace # if needed, set the texture too setTexIfNoShaders(obj)
def __init__(self, win, filename="", units='pix', size=None, pos=(0.0, 0.0), ori=0.0, flipVert=False, flipHoriz=False, color=(1.0, 1.0, 1.0), colorSpace='rgb', opacity=1.0, volume=1.0, name='', loop=False, autoLog=True, depth=0.0, noAudio=False, vframe_callback=None, fps=None, interpolate=True): """ :Parameters: filename : a string giving the relative or absolute path to the movie. flipVert : True or *False* If True then the movie will be top-bottom flipped flipHoriz : True or *False* If True then the movie will be right-left flipped volume : The nominal level is 100, and 0 is silence. loop : bool, optional Whether to start the movie over from the beginning if draw is called and the movie is done. """ # what local vars are defined (these are the init params) for use # by __repr__ self._initParams = dir() self._initParams.remove('self') super(MovieStim2, self).__init__(win, units=units, name=name, autoLog=False) # check for pyglet if win.winType != 'pyglet': logging.error( 'Movie stimuli can only be used with a pyglet window') core.quit() self._retracerate = win._monitorFrameRate if self._retracerate is None: self._retracerate = win.getActualFrameRate() if self._retracerate is None: logging.warning("FrameRate could not be supplied by psychopy; " "defaulting to 60.0") self._retracerate = 60.0 self.filename = pathToString(filename) self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.depth = depth self.opacity = float(opacity) self.volume = volume self._av_stream_time_offset = 0.145 self._no_audio = noAudio self._vframe_callback = vframe_callback self.interpolate = interpolate self.useTexSubImage2D = True self._texID = None self._video_stream = cv2.VideoCapture() self._reset() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 self.aspectRatio = self._video_width / float(self._video_height) # size if size is None: self.size = numpy.array([self._video_width, self._video_height], float) elif isinstance(size, (int, float, int)): # treat size as desired width, and calc a height # that maintains the aspect ratio of the video. self.size = numpy.array([size, size / self.aspectRatio], float) else: self.size = val2array(size) self.ori = ori self._updateVertices() # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created {} = {}".format(self.name, self))
def __init__(self, win, filename="", units='pix', size=None, pos=(0.0,0.0), ori=0.0, flipVert=False, flipHoriz=False, color=(1.0,1.0,1.0), colorSpace='rgb', opacity=1.0, volume=1.0, name='', loop=False, autoLog=True, depth=0.0, noAudio=False, vframe_callback=None, fps=None, interpolate = True, ): """ :Parameters: filename : a string giving the relative or absolute path to the movie. flipVert : True or *False* If True then the movie will be top-bottom flipped flipHoriz : True or *False* If True then the movie will be right-left flipped volume : The nominal level is 100, and 0 is silence. loop : bool, optional Whether to start the movie over from the beginning if draw is called and the movie is done. """ # what local vars are defined (these are the init params) for use # by __repr__ self._initParams = dir() self._initParams.remove('self') super(MovieStim3, self).__init__(win, units=units, name=name, autoLog=False) retraceRate = win._monitorFrameRate if retraceRate is None: retraceRate = win.getActualFrameRate() if retraceRate is None: logging.warning("FrameRate could not be supplied by psychopy; defaulting to 60.0") retraceRate = 60.0 self._retraceInterval = 1.0/retraceRate self.filename = filename self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.depth = depth self.opacity = float(opacity) self.interpolate = interpolate self.noAudio = noAudio self._audioStream = None self.useTexSubImage2D = True self._videoClock = Clock() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 #size if size is None: self.size = numpy.array([self._mov.w, self._mov.h], float) else: self.size = val2array(size) self.ori = ori self._updateVertices() #set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" %(self.name, str(self)))
def __init__(self, win, units = None, fieldPos = (0.0,0.0), fieldSize = (1.0,1.0), fieldShape = 'circle', nElements = 100, sizes = 2.0, xys = None, rgbs = None, colors=(1.0,1.0,1.0), colorSpace='rgb', opacities = 1.0, depths = 0, fieldDepth = 0, oris = 0, sfs=1.0, contrs = 1, phases=0, elementTex='sin', elementMask='gauss', texRes=48, interpolate=True, name='', autoLog=True): """ :Parameters: win : a :class:`~psychopy.visual.Window` object (required) units : **None**, 'height', 'norm', 'cm', 'deg' or 'pix' If None then the current units of the :class:`~psychopy.visual.Window` will be used. See :ref:`units` for explanation of other options. fieldPos : The centre of the array of elements fieldSize : The size of the array of elements (this will be overridden by setting explicit xy positions for the elements) fieldShape : The shape of the array ('circle' or 'sqr') nElements : number of elements in the array sizes : an array of sizes Nx1, Nx2 or a single value xys : the xy positions of the elements, relative to the field centre (fieldPos) colors : specifying the color(s) of the elements. Should be Nx1 (different intensities), Nx3 (different colors) or 1x3 (for a single color). colorSpace : The type of color specified is the same as those in other stimuli ('rgb','dkl','lms'...) but note that for this stimulus you cannot currently use text-based colors (e.g. names or hex values) opacities : the opacity of each element (Nx1 or a single value) depths : the depths of the elements (Nx1), relative the overall depth of the field (fieldDepth) fieldDepth : the depth of the field (will be added to the depths of the elements) oris : the orientations of the elements (Nx1 or a single value). oris are in degrees, and can be greater than 360 and smaller than 0. An ori of 0 is vertical, and increasing ori values are increasingly clockwise. sfs : the spatial frequencies of the elements (Nx1, Nx2 or a single value) contrs : the contrasts of the elements, ranging -1 to +1 (Nx1 or a single value) phases : the spatial phase of the texture on the stimulus (Nx1 or a single value) elementTex : the texture, to be used by all elements (e.g. 'sin', 'sqr',.. , 'myTexture.tif', numpy.ones([48,48])) elementMask : the mask, to be used by all elements (e.g. 'circle', 'gauss',... , 'myTexture.tif', numpy.ones([48,48])) texRes : the number of pixels in the textures (overridden if an array or image is provided) name : string The name of the objec to be using during logged messages about this stim """ #what local vars are defined (these are the init params) for use by __repr__ self._initParams = dir() self._initParams.remove('self') self.autoLog=False #until all params are set self.win=win self.name=name #unit conversions if units!=None and len(units): self.units = units else: self.units = win.units if self.units in ['norm','height']: self._winScale=self.units else: self._winScale='pix' #set the window to have pixels coords self.fieldPos = fieldPos self.fieldSize = fieldSize self.fieldShape = fieldShape self.nElements = nElements #info for each element self.sizes = sizes self.xys= xys self.opacities = opacities self.oris = oris self.contrs = contrs self.phases = phases self.needVertexUpdate=True self.needColorUpdate=True self.useShaders=True self.interpolate=interpolate self.fieldDepth=fieldDepth self.depths=depths if self.win.winType != 'pyglet': raise TypeError('ElementArrayStim requires a pyglet context') if not self.win._haveShaders: raise Exception("ElementArrayStim requires shaders support and floating point textures") self.colorSpace=colorSpace if rgbs!=None: logging.warning("Use of the rgb argument to ElementArrayStim is deprecated. Please use colors and colorSpace args instead") self.setColors(rgbs, colorSpace='rgb', log=False) else: self.setColors(colors, colorSpace=colorSpace, log=False) #Deal with input for fieldpos and fieldsize self.fieldPos = val2array(fieldPos, False) self.fieldSize = val2array(fieldSize, False) #create textures self.texRes = texRes self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.setMask(elementMask, log=False) self.setTex(elementTex, log=False) self.setContrs(contrs, log=False) self.setOpacities(opacities, log=False)#opacities is used by setRgbs, so this needs to be early self.setXYs(xys, log=False) self.setOris(oris, log=False) self.setSizes(sizes, log=False) #set sizes before sfs (sfs may need it formatted) self.setSfs(sfs, log=False) self.setPhases(phases, log=False) self._calcFieldCoordsRendered() self._calcSizesRendered() self._calcXYsRendered() self.autoLog= autoLog if autoLog: logging.exp("Created %s = %s" %(self.name, str(self)))
def __init__(self, win, tex="sin", mask="none", units="", pos=(0.0, 0.0), size=None, sf=None, ori=0.0, phase=(0.0, 0.0), texRes=128, rgb=None, dkl=None, lms=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', contrast=1.0, opacity=1.0, depth=0, rgbPedestal=(0.0, 0.0, 0.0), interpolate=False, name=None, autoLog=None, autoDraw=False, maskParams=None): """ """ # Empty docstring. All doc is in attributes # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = dir() for unecess in ['self', 'rgb', 'dkl', 'lms']: self._initParams.remove(unecess) # initialise parent class super(GratingStim, self).__init__(win, units=units, name=name, autoLog=False) # use shaders if available by default, this is a good thing self.__dict__['useShaders'] = win._haveShaders # UGLY HACK: Some parameters depend on each other for processing. # They are set "superficially" here. # TO DO: postpone calls to _createTexture, setColor and # _calcCyclesPerStim whin initiating stimulus self.__dict__['contrast'] = 1 self.__dict__['size'] = 1 self.__dict__['sf'] = 1 self.__dict__['tex'] = tex self.__dict__['maskParams'] = maskParams # initialise textures and masks for stimulus self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.__dict__['texRes'] = texRes # must be power of 2 self.interpolate = interpolate # NB Pedestal isn't currently being used during rendering - this is a # place-holder self.rgbPedestal = val2array(rgbPedestal, False, length=3) # No need to invoke decorator for color updating. It is done just # below. self.__dict__['colorSpace'] = colorSpace if rgb != None: logging.warning("Use of rgb arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(rgb, colorSpace='rgb', log=False) elif dkl != None: logging.warning("Use of dkl arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(dkl, colorSpace='dkl', log=False) elif lms != None: logging.warning("Use of lms arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(lms, colorSpace='lms', log=False) else: self.setColor(color, colorSpace=colorSpace, log=False) # set other parameters self.ori = float(ori) self.phase = val2array(phase, False) self._origSize = None # updated if an image texture is loaded self._requestedSize = size self.size = val2array(size) self.sf = val2array(sf) self.pos = val2array(pos, False, False) self.depth = depth self.tex = tex self.mask = mask self.contrast = float(contrast) self.opacity = float(opacity) self.autoLog = autoLog self.autoDraw = autoDraw # fix scaling to window coords self._calcCyclesPerStim() # generate a displaylist ID self._listID = GL.glGenLists(1) # JRG: doing self._updateList() here means MRO issues for RadialStim, # which inherits from GratingStim but has its own _updateList code. # So don't want to do the update here (= ALSO the init of RadialStim). # Could potentially define a BaseGrating class without # updateListShaders code, and have GratingStim and RadialStim # inherit from it and add their own _updateList stuff. # Seems unnecessary. Instead, simply defer the update to the # first .draw(), should be fast: # self._updateList() # ie refresh display list self._needUpdate = True # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def __init__(self, win, tex="sqrXsqr", mask="none", units="", pos=(0.0, 0.0), size=(1.0, 1.0), radialCycles=3, angularCycles=4, radialPhase=0, angularPhase=0, ori=0.0, texRes=64, angularRes=100, visibleWedge=(0, 360), rgb=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', dkl=None, lms=None, contrast=1.0, opacity=1.0, depth=0, rgbPedestal=(0.0, 0.0, 0.0), interpolate=False, name=None, autoLog=None, maskParams=None): """ """ # Empty docstring on __init__ # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = dir() self._initParams.remove('self') super(RadialStim, self).__init__(win, units=units, name=name, autoLog=False) # start off false # use shaders if available by default, this is a good thing self.useShaders = win._haveShaders # UGLY HACK again. (See same section in GratingStim for ideas) self.__dict__['contrast'] = 1 self.__dict__['size'] = 1 self.__dict__['sf'] = 1 self.__dict__['tex'] = tex # initialise textures for stimulus self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.__dict__['maskParams'] = maskParams self.maskRadialPhase = 0 self.texRes = texRes # must be power of 2 self.interpolate = interpolate self.rgbPedestal = val2array(rgbPedestal, False, length=3) # these are defined for GratingStim but can only cause confusion here self.setSF = None self.setPhase = None self.colorSpace = colorSpace if rgb != None: logging.warning("Use of rgb arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(rgb, colorSpace='rgb', log=False) elif dkl != None: logging.warning("Use of dkl arguments to stimuli are deprecated. " "Please use color and colorSpace args instead") self.setColor(dkl, colorSpace='dkl', log=False) elif lms != None: logging.warning("Use of lms arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(lms, colorSpace='lms', log=False) else: self.setColor(color, log=False) self.ori = float(ori) self.__dict__['angularRes'] = angularRes self.__dict__['radialPhase'] = radialPhase self.__dict__['radialCycles'] = radialCycles self.__dict__['visibleWedge'] = numpy.array(visibleWedge) self.__dict__['angularCycles'] = angularCycles self.__dict__['angularPhase'] = angularPhase self.pos = numpy.array(pos, float) self.depth = depth self.__dict__['sf'] = 1 self.size = val2array(size, False) self.tex = tex self.mask = mask self.contrast = float(contrast) self.opacity = float(opacity) # self._updateEverything() # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def __init__(self, win, units=None, fieldPos=(0.0, 0.0), fieldSize=(1.0, 1.0), fieldShape='circle', nElements=100, sizes=2.0, xys=None, rgbs=None, colors=(1.0, 1.0, 1.0), colorSpace='rgb', opacities=1.0, depths=0, fieldDepth=0, oris=0, sfs=1.0, contrs=1, phases=0, elementTex='sin', elementMask='gauss', texRes=48, interpolate=True, name=None, autoLog=None, maskParams=None): """ :Parameters: win : a :class:`~psychopy.visual.Window` object (required) units : **None**, 'height', 'norm', 'cm', 'deg' or 'pix' If None then the current units of the :class:`~psychopy.visual.Window` will be used. See :ref:`units` for explanation of other options. nElements : number of elements in the array. """ # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = dir() self._initParams.remove('self') super(ElementArrayStim, self).__init__(name=name, autoLog=False) self.autoLog = False # until all params are set self.win = win # Not pretty (redefined later) but it works! self.__dict__['texRes'] = texRes self.__dict__['maskParams'] = maskParams # unit conversions if units != None and len(units): self.units = units else: self.units = win.units self.__dict__['fieldShape'] = fieldShape self.nElements = nElements # info for each element self.__dict__['sizes'] = sizes self.verticesBase = xys self._needVertexUpdate = True self._needColorUpdate = True self.useShaders = True self.interpolate = interpolate self.__dict__['fieldDepth'] = fieldDepth self.__dict__['depths'] = depths if self.win.winType != 'pyglet': raise TypeError('ElementArrayStim requires a pyglet context') if not self.win._haveShaders: raise Exception("ElementArrayStim requires shaders support" " and floating point textures") self.colorSpace = colorSpace if rgbs != None: msg = ("Use of the rgb argument to ElementArrayStim is deprecated" ". Please use colors and colorSpace args instead") logging.warning(msg) self.setColors(rgbs, colorSpace='rgb', log=False) else: self.setColors(colors, colorSpace=colorSpace, log=False) # Deal with input for fieldpos and fieldsize self.__dict__['fieldPos'] = val2array(fieldPos, False, False) self.__dict__['fieldSize'] = val2array(fieldSize, False) # create textures self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.setMask(elementMask, log=False) self.texRes = texRes self.setTex(elementTex, log=False) self.setContrs(contrs, log=False) # opacities is used by setRgbs, so this needs to be early self.setOpacities(opacities, log=False) self.setXYs(xys, log=False) self.setOris(oris, log=False) # set sizes before sfs (sfs may need it formatted) self.setSizes(sizes, log=False) self.setSfs(sfs, log=False) self.setPhases(phases, log=False) self._updateVertices() # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
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). OBS: log argument is deprecated - has no effect now. Logging should be done when setColor() is called. """ #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 is 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 operation not in ('', None): raise TypeError('Cannot do operations on named or hex color') 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 string, do check and conversion of scalars, sequences and other stuff. else: color = val2array(color, length=3) # enforces length 1 or 3 if color is 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 #check if colorSpace is given and use obj.colorSpace if not if colorSpace is 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 in ('named', 'hex'): 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 if colorSpace == 'named': obj.__dict__[colorAttrib] = color # operations don't make sense for named else: setAttribute(obj, colorAttrib, color, log=False, operation=operation, stealth=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)
def __init__(self, win, tex="sqrXsqr", mask="none", units="", pos=(0.0, 0.0), size=(1.0, 1.0), radialCycles=3, angularCycles=4, radialPhase=0, angularPhase=0, ori=0.0, texRes=64, angularRes=100, visibleWedge=(0, 360), rgb=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', dkl=None, lms=None, contrast=1.0, opacity=1.0, depth=0, rgbPedestal=(0.0, 0.0, 0.0), interpolate=False, name='', autoLog=True): """ :Parameters: texRes : (default= *128* ) resolution of the texture (if not loading from an image file) angularRes : (default= *100* ) 100, the number of triangles used to make the sti radialPhase : the phase of the texture from the centre to the perimeter of the stimulus (in radians) angularPhase : the phase of the texture around the stimulus (in radians) """ #what local vars are defined (these are the init params) for use by __repr__ self._initParams = dir() self._initParams.remove('self') super(RadialStim, self).__init__(win, units=units, name=name, autoLog=False) #autolog should start off false self.useShaders = win._haveShaders #use shaders if available by default, this is a good thing # UGLY HACK again. (See same section in GratingStim for ideas) self.__dict__['contrast'] = 1 self.__dict__['size'] = 1 self.__dict__['sf'] = 1 self.__dict__['tex'] = tex #initialise textures for stimulus self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.maskParams = None self.maskRadialPhase = 0 self.texRes = texRes #must be power of 2 self.interpolate = interpolate self.rgbPedestal = val2array(rgbPedestal, False, length=3) #these are defined by the GratingStim but will just cause confusion here! self.setSF = None self.setPhase = None self.colorSpace = colorSpace if rgb != None: logging.warning( "Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead" ) self.setColor(rgb, colorSpace='rgb') elif dkl != None: logging.warning( "Use of dkl arguments to stimuli are deprecated. Please use color and colorSpace args instead" ) self.setColor(dkl, colorSpace='dkl') elif lms != None: logging.warning( "Use of lms arguments to stimuli are deprecated. Please use color and colorSpace args instead" ) self.setColor(lms, colorSpace='lms') else: self.setColor(color) self.ori = float(ori) self.angularRes = angularRes self.radialPhase = radialPhase self.radialCycles = radialCycles self.visibleWedge = visibleWedge self.angularCycles = angularCycles self.angularPhase = angularPhase self.pos = numpy.array(pos, float) self.depth = depth self.__dict__['sf'] = 1 self.size = val2array(size, False) self.tex = tex self.mask = mask self.contrast = float(contrast) self.opacity = float(opacity) # self._triangleWidth = pi * 2 / self.angularRes self._angles = numpy.arange(0, pi * 2, self._triangleWidth, dtype='float64') #which vertices are visible? self._visible = (self._angles >= (self.visibleWedge[0] * pi / 180) ) #first edge of wedge self._visible[(self._angles + self._triangleWidth) * 180 / pi > ( self.visibleWedge[1])] = False #second edge of wedge self._nVisible = numpy.sum(self._visible) * 3 self._updateTextureCoords() self._updateMaskCoords() self._updateVerticesBase() self._updateVertices() if not self.useShaders: #generate a displaylist ID self._listID = GL.glGenLists(1) self._updateList() #ie refresh display list #set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" % (self.name, repr(self)))
def __init__( self, win, filename="", units="pix", size=None, pos=(0.0, 0.0), ori=0.0, flipVert=False, flipHoriz=False, color=(1.0, 1.0, 1.0), colorSpace="rgb", opacity=1.0, volume=1.0, name="", loop=False, autoLog=True, depth=0.0, noAudio=False, vframe_callback=None, fps=None, interpolate=True, ): """ :Parameters: filename : a string giving the relative or absolute path to the movie. flipVert : True or *False* If True then the movie will be top-bottom flipped flipHoriz : True or *False* If True then the movie will be right-left flipped volume : The nominal level is 100, and 0 is silence. loop : bool, optional Whether to start the movie over from the beginning if draw is called and the movie is done. """ # what local vars are defined (these are the init params) for use # by __repr__ self._initParams = dir() self._initParams.remove("self") super(MovieStim2, self).__init__(win, units=units, name=name, autoLog=False) # check for pyglet if win.winType != "pyglet": logging.error("Movie stimuli can only be used with a pyglet window") core.quit() self._retracerate = win._monitorFrameRate if self._retracerate is None: self._retracerate = win.getActualFrameRate() if self._retracerate is None: logging.warning("FrameRate could not be supplied by psychopy; defaulting to 60.0") self._retracerate = 60.0 self.filename = filename self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.depth = depth self.opacity = float(opacity) self.volume = volume self._av_stream_time_offset = 0.145 self._no_audio = noAudio self._vframe_callback = vframe_callback self.interpolate = interpolate self.useTexSubImage2D = True self._texID = None self._video_stream = cv2.VideoCapture() self._reset() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 self.aspectRatio = self._video_width / float(self._video_height) # size if size is None: self.size = numpy.array([self._video_width, self._video_height], float) elif isinstance(size, (int, float, long)): # treat size as desired width, and calc a height # that maintains the aspect ratio of the video. self.size = numpy.array([size, size / self.aspectRatio], float) else: self.size = val2array(size) self.ori = ori self._updateVertices() # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def __init__(self, win, units ='', nDots =1, coherence =0.5, fieldPos =(0.0,0.0), fieldSize = (1.0,1.0), fieldShape = 'sqr', dotSize =2.0, dotLife = 3, dir =0.0, speed =0.5, rgb =None, color=(1.0,1.0,1.0), colorSpace='rgb', opacity = 1.0, contrast = 1.0, depth =0, element=None, signalDots='same', noiseDots='direction', name='', autoLog=True): """ :Parameters: nDots : int number of dots to be generated fieldPos : (x,y) or [x,y] specifying the location of the centre of the stimulus. fieldSize : (x,y) or [x,y] or single value (applied to both dimensions) Sizes can be negative and can extend beyond the window. fieldShape : *'sqr'* or 'circle' Defines the envelope used to present the dots dotSize specified in pixels (overridden if `element` is specified) dotLife : int Number of frames each dot lives for (default=3, -1=infinite) dir : float (degrees) direction of the coherent dots speed : float speed of the dots (in *units*/frame) signalDots : 'same' or *'different'* If 'same' then the signal and noise dots are constant. If different then the choice of which is signal and which is noise gets randomised on each frame. This corresponds to Scase et al's (1996) categories of RDK. noiseDots : *'direction'*, 'position' or 'walk' Determines the behaviour of the noise dots, taken directly from Scase et al's (1996) categories. For 'position', noise dots take a random position every frame. For 'direction' noise dots follow a random, but constant direction. For 'walk' noise dots vary their direction every frame, but keep a constant speed. element : *None* or a visual stimulus object This can be any object that has a ``.draw()`` method and a ``.setPos([x,y])`` method (e.g. a GratingStim, TextStim...)!! See `ElementArrayStim` for a faster implementation of this idea. """ #what local vars are defined (these are the init params) for use by __repr__ self._initParams = __builtins__['dir']() self._initParams.remove('self') BaseVisualStim.__init__(self, win, units=units, name=name, autoLog=False)#set autoLog at end of init self.nDots = nDots #pos and size are ambiguous for dots so DotStim explicitly has #fieldPos = pos, fieldSize=size and then dotSize as additional param self.fieldPos = self.pos = val2array(fieldPos, False, False) self.fieldSize = self.size = val2array(fieldSize, False) if type(dotSize) in [tuple,list]: self.dotSize = numpy.array(dotSize) else: self.dotSize=dotSize self.fieldShape = fieldShape self.dir = dir self.speed = speed self.element = element self.dotLife = dotLife self.signalDots = signalDots self.noiseDots = noiseDots self.opacity = float(opacity) self.contrast = float(contrast) self.useShaders=False#not needed for dots? self.colorSpace=colorSpace if rgb!=None: logging.warning("Use of rgb arguments to stimuli are deprecated. Please use color and colorSpace args instead") self.setColor(rgb, colorSpace='rgb') else: self.setColor(color) self.depth=depth #initialise the dots themselves - give them all random dir and then #fix the first n in the array to have the direction specified self.coherence=round(coherence*self.nDots)/self.nDots#store actual coherence self. _verticesBase = self._dotsXY = self._newDotsXY(self.nDots) #initialise a random array of X,Y self._dotsSpeed = numpy.ones(self.nDots, 'f')*self.speed#all dots have the same speed self._dotsLife = abs(dotLife)*numpy.random.rand(self.nDots)#abs() means we can ignore the -1 case (no life) #determine which dots are signal self._signalDots = numpy.zeros(self.nDots, dtype=bool) self._signalDots[0:int(self.coherence*self.nDots)]=True #numpy.random.shuffle(self._signalDots)#not really necessary #set directions (only used when self.noiseDots='direction') self._dotsDir = numpy.random.rand(self.nDots)*2*pi self._dotsDir[self._signalDots] = self.dir*pi/180 self._update_dotsXY() self.autoLog= autoLog if autoLog: logging.exp("Created %s = %s" %(self.name, str(self)))
def __init__(self, win, units='', nDots=1, coherence=0.5, fieldPos=(0.0, 0.0), fieldSize=(1.0, 1.0), fieldShape='sqr', dotSize=2.0, dotLife=3, dir=0.0, speed=0.5, rgb=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', opacity=1.0, contrast=1.0, depth=0, element=None, signalDots='same', noiseDots='direction', name=None, autoLog=None): """ :Parameters: fieldSize : (x,y) or [x,y] or single value (applied to both dimensions). Sizes can be negative and can extend beyond the window. """ # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = __builtins__['dir']() self._initParams.remove('self') super(DotStim, self).__init__(win, units=units, name=name, autoLog=False) # set at end of init self.nDots = nDots # pos and size are ambiguous for dots so DotStim explicitly has # fieldPos = pos, fieldSize=size and then dotSize as additional param self.fieldPos = fieldPos # self.pos is also set here self.fieldSize = val2array(fieldSize, False) # self.size is also set if type(dotSize) in [tuple, list]: self.dotSize = numpy.array(dotSize) else: self.dotSize = dotSize self.fieldShape = fieldShape self.__dict__['dir'] = dir self.speed = speed self.element = element self.dotLife = dotLife self.signalDots = signalDots self.opacity = float(opacity) self.contrast = float(contrast) self.useShaders = False # not needed for dots? self.colorSpace = colorSpace if rgb != None: logging.warning("Use of rgb arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(rgb, colorSpace='rgb', log=False) else: self.setColor(color, log=False) self.depth = depth # initialise the dots themselves - give them all random dir and then # fix the first n in the array to have the direction specified self.coherence = coherence # using the attributeSetter self.noiseDots = noiseDots # initialise a random array of X,Y self._verticesBase = self._dotsXY = self._newDotsXY(self.nDots) # all dots have the same speed self._dotsSpeed = numpy.ones(self.nDots, 'f') * self.speed # abs() means we can ignore the -1 case (no life) self._dotsLife = abs(dotLife) * numpy.random.rand(self.nDots) # numpy.random.shuffle(self._signalDots) # not really necessary # set directions (only used when self.noiseDots='direction') self._dotsDir = numpy.random.rand(self.nDots) * 2 * pi self._dotsDir[self._signalDots] = self.dir * pi / 180 self._update_dotsXY() # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))
def __init__(self, win, filename = "", units = 'pix', size = None, pos =(0.0,0.0), ori =0.0, flipVert = False, flipHoriz = False, color=(1.0,1.0,1.0), colorSpace='rgb', opacity=1.0, volume=1.0, name=None, loop=False, autoLog=None, depth=0.0,): """ :Parameters: filename : a string giving the relative or absolute path to the movie. Can be any movie that AVbin can read (e.g. mpeg, DivX) flipVert : True or *False* If True then the movie will be top-bottom flipped flipHoriz : True or *False* If True then the movie will be right-left flipped volume : The nominal level is 1.0, and 0.0 is silence, see pyglet.media.Player loop : bool, optional Whether to start the movie over from the beginning if draw is called and the movie is done. """ #what local vars are defined (these are the init params) for use by __repr__ self._initParams = dir() self._initParams.remove('self') super(MovieStim, self).__init__(win, units=units, name=name, autoLog=False) self._verticesBase *= numpy.array([[-1,1]])#or the movie is flipped if not havePygletMedia: raise ImportError, """pyglet.media is needed for MovieStim and could not be imported. This can occur for various reasons; - psychopy.visual was imported too late (after a lib that uses scipy) - no audio output is enabled (no audio card or no speakers attached) - avbin is not installed """ self._movie=None # the actual pyglet media object self._player=pyglet.media.ManagedSoundPlayer() self._player.volume=volume try: self._player_default_on_eos = self._player.on_eos except: self._player_default_on_eos = self._player._on_eos #from pyglet 1.1.4? self.filename=filename self.duration=None self.loop = loop if loop and pyglet.version>='1.2': logging.error("looping of movies is not currently supported for pyglet>=1.2 only for version 1.1.4") self.loadMovie( self.filename ) self.format=self._movie.video_format self.pos = numpy.asarray(pos, float) self.depth=depth self.flipVert = flipVert self.flipHoriz = flipHoriz self.opacity = float(opacity) self.status=NOT_STARTED #size if size is None: self.size= numpy.array([self.format.width, self.format.height] , float) else: self.size = val2array(size) self.ori = ori self._updateVertices() #check for pyglet if win.winType!='pyglet': logging.error('Movie stimuli can only be used with a pyglet window') core.quit() # set autoLog now that params have been initialised self.__dict__['autoLog'] = autoLog or autoLog is None and self.win.autoLog if self.autoLog: logging.exp("Created %s = %s" %(self.name, str(self)))
def __init__(self, win, filename="", units='pix', size=None, pos=(0.0, 0.0), ori=0.0, flipVert=False, flipHoriz=False, color=(1.0, 1.0, 1.0), colorSpace='rgb', opacity=1.0, volume=1.0, name='', loop=False, autoLog=True, depth=0.0, noAudio=False, vframe_callback=None, fps=None, interpolate=True): # what local vars are defined (these are the init params) for use # by __repr__ self._initParams = dir() self._initParams.remove('self') super(MovieStim3, self).__init__(win, units=units, name=name, autoLog=False) retraceRate = win._monitorFrameRate if retraceRate is None: retraceRate = win.getActualFrameRate() if retraceRate is None: logging.warning("FrameRate could not be supplied by psychopy; " "defaulting to 60.0") retraceRate = 60.0 self._retraceInterval = 1.0 / retraceRate self.filename = pathToString(filename) self.loop = loop self.flipVert = flipVert self.flipHoriz = flipHoriz self.pos = numpy.asarray(pos, float) self.depth = depth self.opacity = opacity self.interpolate = interpolate self.noAudio = noAudio self._audioStream = None self.useTexSubImage2D = True if noAudio: # to avoid dependency problems in silent movies self.sound = None else: from psychopy import sound self.sound = sound # set autoLog (now that params have been initialised) self.autoLog = autoLog if autoLog: logging.exp("Created %s = %s" % (self.name, str(self))) self._videoClock = Clock() self.loadMovie(self.filename) self.setVolume(volume) self.nDroppedFrames = 0 # size if size is None: self.size = numpy.array([self._mov.w, self._mov.h], float) else: self.size = val2array(size) self.ori = ori self._updateVertices()
def __init__(self, win, tex="sin", mask="none", units="", pos=(0.0, 0.0), size=None, sf=None, ori=0.0, phase=(0.0, 0.0), texRes=128, rgb=None, dkl=None, lms=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', contrast=1.0, opacity=1.0, depth=0, rgbPedestal=(0.0, 0.0, 0.0), interpolate=False, blendmode='avg', name=None, autoLog=None, autoDraw=False, maskParams=None): """ """ # Empty docstring. All doc is in attributes # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = dir() for unecess in ['self', 'rgb', 'dkl', 'lms']: self._initParams.remove(unecess) # initialise parent class super(GratingStim, self).__init__(win, units=units, name=name, autoLog=False) # use shaders if available by default, this is a good thing self.__dict__['useShaders'] = win._haveShaders # UGLY HACK: Some parameters depend on each other for processing. # They are set "superficially" here. # TO DO: postpone calls to _createTexture, setColor and # _calcCyclesPerStim whin initiating stimulus self.__dict__['contrast'] = 1 self.__dict__['size'] = 1 self.__dict__['sf'] = 1 self.__dict__['tex'] = tex self.__dict__['maskParams'] = maskParams # initialise textures and masks for stimulus self._texID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._texID)) self._maskID = GL.GLuint() GL.glGenTextures(1, ctypes.byref(self._maskID)) self.__dict__['texRes'] = texRes # must be power of 2 self.interpolate = interpolate # NB Pedestal isn't currently being used during rendering - this is a # place-holder self.rgbPedestal = val2array(rgbPedestal, False, length=3) # No need to invoke decorator for color updating. It is done just # below. self.__dict__['colorSpace'] = colorSpace if rgb != None: logging.warning("Use of rgb arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(rgb, colorSpace='rgb', log=False) elif dkl != None: logging.warning("Use of dkl arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(dkl, colorSpace='dkl', log=False) elif lms != None: logging.warning("Use of lms arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.setColor(lms, colorSpace='lms', log=False) else: self.setColor(color, colorSpace=colorSpace, log=False) # set other parameters self.ori = float(ori) self.phase = val2array(phase, False) self._origSize = None # updated if an image texture is loaded self._requestedSize = size self.size = val2array(size) self.sf = val2array(sf) self.pos = val2array(pos, False, False) self.depth = depth self.tex = tex self.mask = mask self.contrast = float(contrast) self.opacity = float(opacity) self.autoLog = autoLog self.autoDraw = autoDraw self.blendmode=blendmode # fix scaling to window coords self._calcCyclesPerStim() # generate a displaylist ID self._listID = GL.glGenLists(1) # JRG: doing self._updateList() here means MRO issues for RadialStim, # which inherits from GratingStim but has its own _updateList code. # So don't want to do the update here (= ALSO the init of RadialStim). # Could potentially define a BaseGrating class without # updateListShaders code, and have GratingStim and RadialStim # inherit from it and add their own _updateList stuff. # Seems unnecessary. Instead, simply defer the update to the # first .draw(), should be fast: # self._updateList() # ie refresh display list self._needUpdate = True # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created {} = {}".format(self.name, self))
def __init__(self, win, units='', nDots=1, coherence=0.5, fieldPos=(0.0, 0.0), fieldSize=(1.0, 1.0), fieldShape='sqr', fieldAnchor="center", dotSize=2.0, dotLife=3, dir=0.0, speed=0.5, rgb=None, color=(1.0, 1.0, 1.0), colorSpace='rgb', opacity=None, contrast=1.0, depth=0, element=None, signalDots='same', noiseDots='direction', name=None, autoLog=None): """ Parameters ---------- win : window.Window Window this stimulus is associated with. units : str Units to use. nDots : int Number of dots to present in the field. coherence : float Proportion of dots which are coherent. This value can be set using the `coherence` property after initialization. fieldPos : array_like (x,y) or [x,y] position of the field. This value can be set using the `fieldPos` property after initialization. fieldSize : array_like, int or float (x,y) or [x,y] or single value (applied to both dimensions). Sizes can be negative and can extend beyond the window. This value can be set using the `fieldSize` property after initialization. fieldShape : str Defines the envelope used to present the dots. If changed while drawing by setting the `fieldShape` property, dots outside new envelope will be respawned., valid values are 'square', 'sqr' or 'circle'. dotSize : array_like or float Size of the dots. If given an array, the sizes of individual dots will be set. The array must have length `nDots`. If a single value is given, all dots will be set to the same size. dotLife : int Lifetime of a dot in frames. Dot lives are initiated randomly from a uniform distribution from 0 to dotLife. If changed while drawing, the lives of all dots will be randomly initiated again. A value of -1 results in dots having an infinite lifetime. This value can be set using the `dotLife` property after initialization. dir : float Direction of the coherent dots in degrees. At 0 degrees, coherent dots will move from left to right. Increasing the angle will rotate the direction counter-clockwise. This value can be set using the `dir` property after initialization. speed : float Speed of the dots (in *units* per frame). This value can be set using the `speed` property after initialization. rgb : array_like, optional Color of the dots in form (r, g, b) or [r, g, b]. **Deprecated**, use `color` instead. color : array_like or str Color of the dots in form (r, g, b) or [r, g, b]. colorSpace : str Colorspace to use. opacity : float Opacity of the dots from 0.0 to 1.0. contrast : float Contrast of the dots 0.0 to 1.0. This value is simply multiplied by the `color` value. depth : float **Deprecated**, depth is now controlled simply by drawing order. element : object This can be any object that has a ``.draw()`` method and a ``.setPos([x,y])`` method (e.g. a GratingStim, TextStim...)!! DotStim assumes that the element uses pixels as units. ``None`` defaults to dots. signalDots : str If 'same' then the signal and noise dots are constant. If different then the choice of which is signal and which is noise gets randomised on each frame. This corresponds to Scase et al's (1996) categories of RDK. This value can be set using the `signalDots` property after initialization. noiseDots : str Determines the behaviour of the noise dots, taken directly from Scase et al's (1996) categories. For 'position', noise dots take a random position every frame. For 'direction' noise dots follow a random, but constant direction. For 'walk' noise dots vary their direction every frame, but keep a constant speed. This value can be set using the `noiseDots` property after initialization. name : str, optional Optional name to use for logging. autoLog : bool Enable automatic logging. """ # what local vars are defined (these are the init params) for use by # __repr__ self._initParams = __builtins__['dir']() self._initParams.remove('self') super(DotStim, self).__init__(win, units=units, name=name, autoLog=False) # set at end of init self.nDots = nDots # pos and size are ambiguous for dots so DotStim explicitly has # fieldPos = pos, fieldSize=size and then dotSize as additional param self.fieldPos = fieldPos # self.pos is also set here self.fieldSize = val2array(fieldSize, False) # self.size is also set if type(dotSize) in (tuple, list): self.dotSize = np.array(dotSize) else: self.dotSize = dotSize if self.win.useRetina: self.dotSize *= 2 # double dot size to make up for 1/2-size pixels self.fieldShape = fieldShape self.__dict__['dir'] = dir self.speed = speed self.element = element self.dotLife = dotLife self.signalDots = signalDots if rgb != None: logging.warning("Use of rgb arguments to stimuli are deprecated." " Please use color and colorSpace args instead") self.colorSpace = 'rgba' self.color = rgb else: self.colorSpace = colorSpace self.color = color self.opacity = opacity self.contrast = float(contrast) self.depth = depth # initialise the dots themselves - give them all random dir and then # fix the first n in the array to have the direction specified self.coherence = coherence # using the attributeSetter self.noiseDots = noiseDots # initialise a random array of X,Y self.vertices = self._verticesBase = self._dotsXY = self._newDotsXY( self.nDots) # all dots have the same speed self._dotsSpeed = np.ones(self.nDots, dtype=float) * self.speed # abs() means we can ignore the -1 case (no life) self._dotsLife = np.abs(dotLife) * np.random.rand(self.nDots) # pre-allocate array for flagging dead dots self._deadDots = np.zeros(self.nDots, dtype=bool) # set directions (only used when self.noiseDots='direction') self._dotsDir = np.random.rand(self.nDots) * _2pi self._dotsDir[self._signalDots] = self.dir * _piOver180 self._update_dotsXY() self.anchor = fieldAnchor # set autoLog now that params have been initialised wantLog = autoLog is None and self.win.autoLog self.__dict__['autoLog'] = autoLog or wantLog if self.autoLog: logging.exp("Created %s = %s" % (self.name, str(self)))