def draw_polygon(self, pointlist, colour=None, color=None, pw=1, \ fill=True): """Draws a polygon on the screen arguments pointlist -- a list of (x,y) tuples resembling the cornerpoints of the polygon keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) pw -- penwidth: polygon line thickness (default = 1) fill -- Boolean indicating whether polygon should be filled or not (default = False) returns Nothing -- draws a polygon on (PyGame) or adds a ShapeStim stimulus to (PsychoPy) the self.screen property """ if color is None and colour is None: pass elif color is None and colour is not None: pass elif color is not None and colour is None: colour = color elif colour != color: raise Exception( "The arguments 'color' and 'colour' are the same, but set to different values: color={}, colour={}" .format(color, colour)) if colour is None: colour = self.fgc colour = rgb2psychorgb(colour) pl = [] for pos in pointlist: pl.append(pos2psychopos(pos, dispsize=self.dispsize)) if fill: self.screen.append(ShapeStim(pygaze.expdisplay, lineWidth=pw, \ lineColor=colour, lineColorSpace='rgb', fillColor=colour, \ fillColorSpace='rgb',vertices=pl, closeShape=True)) else: self.screen.append(ShapeStim(pygaze.expdisplay, lineWidth=pw, \ lineColor=colour, lineColorSpace='rgb', \ fillColor=rgb2psychorgb(self.bgc), fillColorSpace='rgb', \ vertices=pl, closeShape=True))
def draw_polygon(self, pointlist, colour=None, pw=1, fill=True): """Draws a polygon on the screen arguments pointlist -- a list of (x,y) tuples resembling the cornerpoints of the polygon keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) pw -- penwidth: polygon line thickness (default = 1) fill -- Boolean indicating whether polygon should be filled or not (default = False) returns Nothing -- draws a polygon on (PyGame) or adds a ShapeStim stimulus to (PsychoPy) the self.screen property """ if colour == None: colour = self.fgc colour = rgb2psychorgb(colour) pl = [] for pos in pointlist: pl.append(pos2psychopos(pos,dispsize=self.dispsize)) if fill: self.screen.append(ShapeStim(pygaze.expdisplay, lineWidth=pw, lineColor=colour, lineColorSpace='rgb', fillColor=colour, fillColorSpace='rgb',vertices=pl, closeShape=True)) else: self.screen.append(ShapeStim(pygaze.expdisplay, lineWidth=pw, lineColor=colour, lineColorSpace='rgb', fillColor=rgb2psychorgb(self.bgc), fillColorSpace='rgb',vertices=pl, closeShape=True))
def __init__(self, dispsize=settings.DISPSIZE, fgc=settings.FGC, bgc=settings.BGC, screennr=settings.SCREENNR, screen=None, **args): # See _display.basedisplay.BaseDisplay for documentation # try to import copy docstring (but ignore it if it fails, as we do # not need it for actual functioning of the code) try: copy_docstr(BaseDisplay, PsychoPyDisplay) except: # we're not even going to show a warning, since the copied # docstring is useful for code editors; these load the docs # in a non-verbose manner, so warning messages would be lost pass self.dispsize = dispsize self.fgc = fgc self.bgc = bgc self.screennr = screennr self.mousevis = False # create window pygaze.expdisplay = Window(size=self.dispsize, pos=None, color=rgb2psychorgb(self.bgc), colorSpace='rgb', fullscr=settings.FULLSCREEN, screen=self.screennr, units='pix') # set mouse visibility pygaze.expdisplay.setMouseVisible(self.mousevis) # get screen in window if screen: for s in screen.screen: s.draw()
def __init__(self, dispsize=settings.DISPSIZE, fgc=settings.FGC, bgc=settings.BGC, screennr=settings.SCREENNR, monitor = None, screen=None, **args): # See _display.basedisplay.BaseDisplay for documentation # try to import copy docstring (but ignore it if it fails, as we do # not need it for actual functioning of the code) try: copy_docstr(BaseDisplay, PsychoPyDisplay) except: # we're not even going to show a warning, since the copied # docstring is useful for code editors; these load the docs # in a non-verbose manner, so warning messages would be lost pass self.dispsize = dispsize self.fgc = fgc self.bgc = bgc self.screennr = screennr self.mousevis = False self.monitor = monitor # create window pygaze.expdisplay = Window(size=self.dispsize, pos=None, color=rgb2psychorgb(self.bgc), colorSpace='rgb', fullscr=settings.FULLSCREEN, monitor=self.monitor, screen=self.screennr, units='pix') # set mouse visibility pygaze.expdisplay.setMouseVisible(self.mousevis) # get screen in window if screen: for s in screen.screen: s.draw()
def draw_rect(self, colour=None, color=None, x=None, y=None, w=50, h=50, \ pw=1, fill=False): """Draws a rectangle on the screen arguments None keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) x -- x coordinate of the rectangle or None for a horizontal centrally drawn rectangle (default = None) y -- y coordinate of the rectangle or None for a vertical centrally drawn rectangle (default = None) w -- width of the rectangle (default = 50) h -- height of the rectangle (default = 50) pw -- penwidth: ellipse line thickness (default = 1) fill -- Boolean indicating whether rectangle should be filled or not (default = False) returns Nothing -- draws a rectangle on (PyGame) or adds a GratinsStim stimulus to (PsychoPy) the self.screen property """ if color is None and colour is None: pass elif color is None and colour is not None: pass elif color is not None and colour is None: colour = color elif colour != color: raise Exception( "The arguments 'color' and 'colour' are the same, but set to different values: color={}, colour={}" .format(color, colour)) if colour is None: colour = self.fgc if x is None: x = self.dispsize[0] / 2 if y is None: y = self.dispsize[1] / 2 pos = x, y colour = rgb2psychorgb(colour) pos = pos2psychopos(pos, dispsize=self.dispsize) pos = pos[0] + w / 2, pos[1] - h / 2 if fill: self.screen.append(Rect(pygaze.expdisplay, width=w, height=h, \ lineWidth=pw, lineColor=colour, lineColorSpace='rgb', \ fillColor=colour, fillColorSpace='rgb', pos=pos)) else: self.screen.append(Rect(pygaze.expdisplay, width=w, height=h, \ lineWidth=pw, lineColor=colour, lineColorSpace='rgb', \ fillColor=None, pos=pos))
def draw_line(self, colour=None, color=None, spos=None, epos=None, pw=1): """Draws a line on the screen arguments None keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) spos -- line start, an (x,y) position tuple or None for a quarter x and a central y position (default = None) epos -- line end, an (x,y) position tuple or None for a three-quarter x and a central y position (default = None) pw -- penwidth: line thickness (default = 1) returns Nothing -- draws a line on (PyGame) or adds a Line stimulus to (PsychoPy) the self.screen property """ if color is None and colour is None: pass elif color is None and colour is not None: pass elif color is not None and colour is None: colour = color elif colour != color: raise Exception( "The arguments 'color' and 'colour' are the same, but set to different values: color={}, colour={}" .format(color, colour)) if colour is None: colour = self.fgc if spos is None: spos = (int(self.dispsize[0] * 0.25), self.dispsize[1] / 2) if epos is None: epos = (int(self.dispsize[0] * 0.75), self.dispsize[1] / 2) colour = rgb2psychorgb(colour) spos = pos2psychopos(spos, dispsize=self.dispsize) epos = pos2psychopos(epos, dispsize=self.dispsize) # The `Line` class appears to be broken in a recent update of # PsychoPy. Hence the fallback to `ShapeStim`. See also: # <https://groups.google.com/forum/#!topic/psychopy-dev/1sKn6RrqH-8> #self.screen.append(Line(pygaze.expdisplay, start=spos, end=epos, \ # lineColor=colour, lineColorSpace='rgb', lineWidth=pw)) stim = ShapeStim(pygaze.expdisplay, lineWidth=pw, \ vertices=[spos, epos], lineColor=colour) self.screen.append(stim)
def draw_circle(self, colour=None, pos=None, r=50, pw=1, fill=False): """Draws a circle on the screen arguments None keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) pos -- circle center, an (x,y) position tuple or None for a central position (default = None) r -- circle radius (default = 50) pw -- penwidth: circle line thickness (default = 1) fill -- Boolean indicating whether circle should be filled or not (default = False) returns Nothing -- draws a circle on (PyGame) or adds a Circle stimulus to (PsychoPy) the self.screen property """ if colour == None: colour = self.fgc if pos == None: pos = (self.dispsize[0] / 2, self.dispsize[1] / 2) colour = rgb2psychorgb(colour) pos = pos2psychopos(pos, dispsize=self.dispsize) if fill: self.screen.append( Circle(pygaze.expdisplay, radius=r, edges=32, pos=pos, lineWidth=pw, lineColor=colour, lineColorSpace='rgb', fillColor=colour, fillColorSpace='rgb')) else: self.screen.append( Circle(pygaze.expdisplay, radius=r - pw, edges=32, pos=pos, lineWidth=pw, lineColor=colour, lineColorSpace='rgb'))
def draw_ellipse(self, colour=None, x=None, y=None, w=50, h=50, pw=1, fill=False): """Draws an ellipse on the screen arguments None keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) x -- x coordinate of the rectangle in which the ellipse is drawn or None for a horizontal centrally drawn ellipse (default = None) y -- y coordinate of the rectangle in which the ellipse is drawn or None for a vertical centrally drawn ellipse (default = None) w -- width of the rectangle in which the ellipse is drawn (default = 50) h -- height of the rectangle in which the ellipse is drawn (default = 50) pw -- penwidth: circle line thickness (default = 1) fill -- Boolean indicating whether ellipse should be filled or not (default = False) returns Nothing -- draws an ellipse on (PyGame) or adds a GratinsStim stimulus to (PsychoPy) the self.screen property """ if colour == None: colour = self.fgc if x == None: x = 0 if y == None: y = 0 pos = x,y colour = rgb2psychorgb(colour) pos = pos2psychopos(pos,dispsize=self.dispsize) pos = pos[0] + w/2, pos[1] - h/2 if fill: self.screen.append(Circle(pygaze.expdisplay, lineWidth=pw, lineColor=colour, lineColorSpace='rgb', fillColor=colour, fillColorSpace='rgb', pos=pos, size=(w,h))) else: self.screen.append(Circle(pygaze.expdisplay, lineWidth=pw, lineColor=colour, lineColorSpace='rgb', fillColor=None, pos=pos, size=(w,h)))
def draw_text(self, text='text', colour=None, pos=None, center=True, font='mono', fontsize=12, antialias=True): """Draws a text on the screen arguments None keyword arguments text -- string to be displayed (newlines are allowed and will be recognized) (default = 'text') colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) pos -- text position, an (x,y) position tuple or None for a central position (default = None) center -- Boolean indicating is the pos keyword argument should indicate the text center (True) or the top right coordinate (False) (default = True) font -- font name (a string value); should be the name of a font included in the PyGaze resources/fonts directory (default = 'mono') fontsize -- fontsize in pixels (an integer value) (default = 12) antialias -- Boolean indicating whether text should be antialiased or not (default = True) returns Nothing -- renders and draws a surface with text on (PyGame) or adds SimpleTextStim to (PsychoPy) the self.screen property """ if colour == None: colour = self.fgc if pos == None: pos = (self.dispsize[0]/2, self.dispsize[1]/2) if center: align = 'center' else: align = 'left' colour = rgb2psychorgb(colour) pos = pos2psychopos(pos,dispsize=self.dispsize) self.screen.append(TextStim(pygaze.expdisplay, text=str(text), font=font, pos=pos, color=colour, height=fontsize, antialias=antialias, alignHoriz=align, fontFiles=pygaze.FONTFILES, wrapWidth=None))
def draw_line(self, colour=None, spos=None, epos=None, pw=1): """Draws a line on the screen arguments None keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) spos -- line start, an (x,y) position tuple or None for a quarter x and a central y position (default = None) epos -- line end, an (x,y) position tuple or None for a three-quarter x and a central y position (default = None) pw -- penwidth: line thickness (default = 1) returns Nothing -- draws a line on (PyGame) or adds a Line stimulus to (PsychoPy) the self.screen property """ if colour == None: colour = self.fgc if spos == None: spos = (int(self.dispsize[0]*0.25), self.dispsize[1]/2) if epos == None: epos = (int(self.dispsize[0]*0.75), self.dispsize[1]/2) colour = rgb2psychorgb(colour) spos = pos2psychopos(spos,dispsize=self.dispsize) epos = pos2psychopos(epos,dispsize=self.dispsize) # The `Line` class appears to be broken in a recent update of # PsychoPy. Hence the fallback to `ShapeStim`. See also: # <https://groups.google.com/forum/#!topic/psychopy-dev/1sKn6RrqH-8> #self.screen.append(Line(pygaze.expdisplay, start=spos, end=epos, lineColor=colour, lineColorSpace='rgb', lineWidth=pw)) stim = ShapeStim(pygaze.expdisplay, lineWidth=pw, vertices=[spos, epos], lineColor=colour) self.screen.append(stim)
def draw_circle(self, colour=None, pos=None, r=50, pw=1, fill=False): """Draws a circle on the screen arguments None keyword arguments colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) pos -- circle center, an (x,y) position tuple or None for a central position (default = None) r -- circle radius (default = 50) pw -- penwidth: circle line thickness (default = 1) fill -- Boolean indicating whether circle should be filled or not (default = False) returns Nothing -- draws a circle on (PyGame) or adds a Circle stimulus to (PsychoPy) the self.screen property """ if colour == None: colour = self.fgc if pos == None: pos = (self.dispsize[0]/2, self.dispsize[1]/2) colour = rgb2psychorgb(colour) pos = pos2psychopos(pos,dispsize=self.dispsize) if fill: self.screen.append(Circle(pygaze.expdisplay, radius=r, edges=32, pos=pos, lineWidth=pw, lineColor=colour, lineColorSpace='rgb', fillColor=colour, fillColorSpace='rgb')) else: self.screen.append(Circle(pygaze.expdisplay, radius=r-pw, edges=32, pos=pos, lineWidth=pw, lineColor=colour, lineColorSpace='rgb'))
def draw_text(self, text="text", colour=None, color=None, pos=None, \ centre=None, center=None, font="mono", fontsize=12, \ antialias=True, wrap_width=None): """Draws a text on the screen arguments None keyword arguments text -- string to be displayed (newlines are allowed and will be recognized) (default = 'text') colour -- colour for the circle (a colour name (e.g. 'red') or a RGB(A) tuple (e.g. (255,0,0) or (255,0,0,255))) or None for the default foreground colour, self.fgc (default = None) pos -- text position, an (x,y) position tuple or None for a central position (default = None) center -- Boolean indicating is the pos keyword argument should indicate the text centre (True) or the top right coordinate (False) (default = True) font -- font name (a string value); should be the name of a font included in the PyGaze resources/fonts directory (default = 'mono') fontsize -- fontsize in pixels (an integer value) (default = 12) antialias -- Boolean indicating whether text should be antialiased or not (default = True) returns Nothing -- renders and draws a surface with text on (PyGame) or adds SimpleTextStim to (PsychoPy) the self.screen property """ if color is None and colour is None: pass elif color is None and colour is not None: pass elif color is not None and colour is None: colour = color elif colour != color: raise Exception( "The arguments 'color' and 'colour' are the same, but set to different values: color={}, colour={}" .format(color, colour)) if center is None and centre is None: centre = True elif center is None and centre is not None: pass elif center is not None and centre is None: centre = center elif centre != center: raise Exception( "The arguments 'center' and 'centre' are the same, but set to different values: center={}, centre={}" .format(center, centre)) if colour is None: colour = self.fgc if pos is None: pos = (self.dispsize[0] / 2, self.dispsize[1] / 2) if centre: align = "center" else: align = "left" colour = rgb2psychorgb(colour) pos = pos2psychopos(pos, dispsize=self.dispsize) self.screen.append(TextStim(pygaze.expdisplay, text=str(text), \ font=font, pos=pos, color=colour, height=fontsize, \ antialias=antialias, alignHoriz=align, \ fontFiles=pygaze.FONTFILES, wrapWidth=wrap_width)) # PsychoPy deprecated "alignHoriz", but in version 3.2.4 (and maybe # also others, who knows?) its replacements "alignText" and # "anchorHoriz" are unknown keyword arguments to __init__. Yet, # "alignHoriz" does NOT work any longer. I guess alignment is just # broken now? The ugly workaround below will NOT work for those broken # versions of PsychoPy, but will at least not crash them. self.screen[-1].anchorHoriz = align self.screen[-1].alignText = align
def update(self, locs, oris, bgcols, linewidth=None, stimtypes=None): """Updates the locations, colours, line colours, and line widths of this stimulus array. Arguments locs - List of (x,y) tuples that determine the positions of all stimuli. The list's length should be equal to the number of stimuli as defined by nstim. oris - List of integers that determine the orientations of all stimuli. The list's length should be equal to the number of stimuli as defined by nstim. bgcols - List of (r,g,b) tuples that determine the colours of the background to all stimuli. The list's length should be equal to the number of stimuli as defined by nstim. Keyword Arguments linewidth - Integer or a list of integers that determines the width of the lines around stimuli (in pixels), or None to leave the width as it is. Default value is None. stimtypes - String or a list of strings that determines the type of stimulus. Options are 'gabor' and 'noise', or None to not update. Default is None. """ # Convert the linewidth to a list (if necessary). if type(linewidth) in [int, float]: linewidth = len(self._stimindexnrs) * [int(linewidth)] # Convert the stimulus types to a list (if necessary). if type(stimtypes) in [str, unicode]: stimtypes = len(self._stimindexnrs) * [stimtypes] # Loop through all stimuli. # stimnr is a number between 0 and nstim # stimindexnr refers to the index of a stimulus in self.screen for stimnr, stimindexnr in enumerate(self._stimindexnrs): # Update the stimulus location. self.screen[stimindexnr].pos = pos2psychopos(locs[stimnr]) self.screen[self._bgindexnrs[stimnr]].pos = pos2psychopos( locs[stimnr]) self.screen[self._outlineindexnrs[stimnr]].pos = pos2psychopos( locs[stimnr]) # # Update the stimulus colour. # self.screen[stimindexnr].fillColor = rgb2psychorgb(list(oris[stimnr])) # Update the stimulus orientation. self.screen[stimindexnr].setOri(oris[stimnr]) # Update the stimulus background colour self.screen[self._bgindexnrs[stimnr]].fillColor = rgb2psychorgb( list(bgcols[stimnr])) self.screen[self._bgindexnrs[stimnr]].lineColor = rgb2psychorgb( list(bgcols[stimnr])) # Update the stimulus line width and colour. if linewidth != None: self.screen[self._outlineindexnrs[ stimnr]].lineWidth = linewidth[stimnr] if linewidth[stimnr] == PROBELINEWIDTH: self.screen[self._outlineindexnrs[stimnr]].lineColor = \ (1,-1,-1) else: self.screen[self._outlineindexnrs[stimnr]].lineColor = \ (0,0,0) # Update the stimulus texture. if stimtypes != None: if stimtypes[stimnr] == 'gabor': self.screen[stimindexnr].setTex('sin') else: self.screen[stimindexnr].setTex(self._noisetex)
def __init__(self, nstim, locs, oris, linewidth=3, \ stimtypes='gabor', showcolourwheel=False): """Initialises a new StimScreen instance. Arguments nstim - Integer that determines the number of stimuli on this screen. locs - List of (x,y) tuples that determine the positions of all stimuli. The list's length should be equal to the number of stimuli as defined by nstim. oris - List of integers that determine the orientations of all stimuli. The list's length should be equal to the number of stimuli as defined by nstim. Keyword Arguments linewidth - Integer or a list of integers that determines the width of the lines around stimuli (in pixels). Default value is 3. stimtypes - String or a list of strings that determines the type of stimulus. Options are 'gabor' and 'noise'. Default is 'gabor'. showcolourwheel- Boolean that determines whether a central colour wheel should be drawn of not. Default is False. """ # Settings from the constants. self._sf = float(STIMSF) / float(STIMSIZE) self._alpha = STIMALPHA self._contrast = STIMCONTRAST # Noise texture. self._noisetex = numpy.random.rand(STIMNOISERES, STIMNOISERES) # Convert the linewidth to a list (if necessary). if type(linewidth) in [int, float]: linewidth = nstim * [int(linewidth)] # Convert the stimulus types to a list (if necessary). if type(stimtypes) in [str, unicode]: stimtypes = nstim * [stimtypes] # Create a Screen to use its wonderful drawing functions. self.scr = Screen() # Draw the fixation cross. self.scr.draw_fixation(fixtype=FIXTYPE, diameter=FIXSIZE) # Draw the colouw wheel if showcolourwheel: # Load the image. self.scr.draw_image(CWIMG, scale=CWIMGSCALE) # Create an internal list of stimuli (=PsychoPy stimulus instances) by # copying it from the internal screen. self.screen = self.scr.screen # Draw the backgrounds to the stimuli, which will appear in the # background colour initially, but will turn to a different colour to # mark that they are fixated by a participant. # Keep a list of the index numbers of all stimuli. The indices refer # to positions within the self.scr.screen list of PsychoPy stimuli. self._bgindexnrs = [] # Draw the stimuli. for i in range(nstim): # Add the stimulus' index number to the list of indices. self._bgindexnrs.append(len(self.screen)) # Create a new Circle stimulus instance. stim = Circle(pygaze.expdisplay, \ radius=STIMSIZE, \ edges=64, \ pos=pos2psychopos(locs[i]), \ fillColor=rgb2psychorgb(BGC), \ lineColor=rgb2psychorgb(BGC), \ lineWidth=0) # Add the new stimulus to our list of stimuli. self.screen.append(stim) # Keep a list of the index numbers of all stimuli. The indices refer # to positions within the self.scr.screen list of PsychoPy stimuli. self._stimindexnrs = [] self._outlineindexnrs = [] # Draw the stimuli. for i in range(nstim): # Add the stimulus' index number to the list of indices. self._stimindexnrs.append(len(self.screen)) # # Create a new Rect stimulus instance. # stim = Rect(pygaze.expdisplay, \ # pos=pos2psychopos(locs[i]), \ # fillColor=rgb2psychorgb(list(oris[i])), \ # lineColor=rgb2psychorgb(list(linecols[i])), \ # lineWidth=linewidth[i], \ # width=STIMSIZE, \ # height=STIMSIZE) # Create a Gabor-ish GratingStim. if stimtypes[i] == 'gabor': tex = 'sin' else: tex = self._noisetex stim = GratingStim(pygaze.expdisplay, \ pos=pos2psychopos(locs[i]), \ ori=oris[i], \ size=STIMSIZE, \ sf=self._sf, \ opacity=self._alpha, \ contrast=self._contrast, \ tex=tex, \ mask='circle', \ color=(1,1,1) ) # Add the new stimulus to our list of stimuli. self.screen.append(stim) # Add an outline for the stimulus. self._outlineindexnrs.append(len(self.screen)) stim = Circle(pygaze.expdisplay, \ pos=pos2psychopos(locs[i]), \ lineWidth=linewidth[i], \ radius=STIMSIZE//2, \ edges=32, \ closeShape=False, \ fillColor=None, \ lineColor=(0,0,0) ) # Add the new stimulus to our list of stimuli. self.screen.append(stim)