Canvas functions
class Canvas
The Canvas
class is used to present visual stimuli. You generally create a
Canvas
object with the Canvas()
factory function, as described in the section
Creating a Canvas.
Example:
# Create and show a canvas with a central fixation dot
my_canvas = Canvas()
my_canvas.fixdot()
my_canvas.show()
Example:
You can also add Canvas
elements as objects. See also the section on Naming,
accessing, and modifying elements.
# Create a canvas with a fixation dot and a rectangle
my_canvas = Canvas()
my_canvas['my_fixdot'] = FixDot()
my_canvas.show()
- class Canvas
- Things to know
- arrow(sx, sy, ex, ey, body_length=0.8, body_width=0.5, head_width=30, **style_args)
- circle(x, y, r, **style_args)
- clear(*arglist, **kwdict)
- copy(canvas)
- elements_at(x, y)
- ellipse(x, y, w, h, **style_args)
- fixdot(x=None, y=None, style='default', **style_args)
- gabor(x, y, orient, freq, env='gaussian', size=96, stdev=12, phase=0, col1='white', col2='black', bgmode='avg')
- image(fname, center=True, x=None, y=None, scale=None, rotation=None)
- line(sx, sy, ex, ey, **style_args)
- lower_to_bottom(element)
- noise_patch(x, y, env='gaussian', size=96, stdev=12, col1='white', col2='black', bgmode='avg')
- polygon(vertices, **style_args)
- prepare()
- raise_to_top(element)
- rect(x, y, w, h, **style_args)
- rename_element(old_name, new_name)
- show()
- text(text, center=True, x=None, y=None, max_width=None, **style_args)
- text_size(text, center=True, max_width=None, **style_args)
Things to know
Creating a Canvas
You generally create a Canvas
with the Canvas()
factory function:
my_canvas = Canvas()
Optionally, you can pass Style keywords to Canvas()
to set
the default style:
my_canvas = Canvas(color='green')
my_canvas.fixdot() # Will be green
Style keywords
All functions that accept **style_args
take the following keyword arguments:
color
specifies the foreground color. For valid color specifications, see colors.background_color
specifies the background color. For valid color specifications, see colors.fill
indicates whether rectangles, circles, polygons, and ellipses are filled (True
), or drawn as an outline (False
).penwidth
indicates a penwidth in pixels and should beint
orfloat
.html
indicates whether HTML-tags are interpreted, and should beTrue
orFalse
.font_family
is the name of a font family, such as 'sans'.font_size
is a font size in pixels.font_italic
indicates whether text should italics, and should beTrue
orFalse
.font_bold
indicates whether text should bold, and should beTrue
orFalse
.font_underline
indicates whether text should underlined, and should beTrue
orFalse
.
# Draw a green fixation dot
my_canvas = Canvas()
my_canvas.fixdot(color='green')
my_canvas.show()
Style keywords only affect the current drawing operation (except when passed to
Canvas()
while creating the Canvas
). To change the style for all subsequent
drawing operations, set style properties, such as canvas.color
, directly:
# Draw a red cross with a 2px penwidth
my_canvas = Canvas()
my_canvas.color = 'red'
my_canvas.penwidth = 2
my_canvas.line(-10, -10, 10, 10)
my_canvas.line(-10, 10, 10, -10)
my_canvas.show()
Or pass the style properties to Canvas()
:
# Draw a red cross with a 2px penwidth
my_canvas = Canvas(color='red', penwidth=2)
my_canvas.line(-10, -10, 10, 10)
my_canvas.line(-10, 10, 10, -10)
my_canvas.show()
Colors
You can specify colors in the following ways. This includes CSS3-type color specifications, but also supports some extra specifications, such as CIE l a b* color space.
Version note: The hsv
, hsl
, and lab
color spaces are new in v3.3.0.
- Color names: 'red', 'black', etc. A full list of valid color names can be found here.
- Seven-character hexadecimal strings:
#FF0000
,#000000
, etc. Here, values range from00
toFF
, so that#FF0000
is bright red. - Four-character hexadecimal strings:
#F00
,#000
, etc. Here, values range from '0' to 'F' so that#F00
is bright red. - RGB strings:
rgb(255,0,0)
,rgb(0,0,0)
, etc. Here, values range from 0 to 255 so thatrgb(255,0,0)
is bright red. - RGB percentage strings:
rgb(100%,0%,0%)
,rgb(0%,0%,0%)
, etc. Here, values range from 0% to 100% so thatrgb(100%,0%,0%)
is bright red. - RGB tuples:
(255, 0, 0)
,(0, 0 ,0)
, etc. Here, values range from0
to255
so that `(255,0,0)' is bright red. - HSV strings:
hsv(120, 100%, 100%)
. In the HSV color space, the hue parameter is an angle from 0 to 359, and the saturation and value parameters are percentages from 0% to 100%. - HSL strings:
hsl(120, 100%, 50%)
. In the HSL color space, the hue parameter is an angle from 0 to 359, and the saturation and lightness parameters are percentages from 0% to 100%. - LAB strings:
lab(53, -20, 0)
. In the CIELAB color space, the parameters reflect lightness (l*
), green-red axis (a*
, negative is green), and blue-yellow axis (b*
, negative is blue). This uses the D65 white point and the sRGB transfer function, as implemented here. - Luminance values:
255
,0
, etc. Here, values range from0
to255
so that255
is white.
# Various ways to specify green
my_canvas.fixdot(color='green') # Dark green
my_canvas.fixdot(color='#00ff00')
my_canvas.fixdot(color='#0f0')
my_canvas.fixdot(color='rgb(0, 255, 0)')
my_canvas.fixdot(color='rgb(0%, 100%, 0%)')
my_canvas.fixdot(color='hsl(100, 100%, 50%)')
my_canvas.fixdot(color='hsv(0, 100%, 100%)')
my_canvas.fixdot(color='lab(53, -20, 0)') # Dark green
my_canvas.fixdot(color=(0, 255, 0)) # Specify a luminance value (white)
Naming, accessing, and modifying elements
As of OpenSesame 3.2, the Canvas
supports an object-based interface that allows
you to name elements, and to access and modify elements individually, without
having to redraw the entire Canvas
.
For example, the following will first add a red Line
element to a Canvas
and show it, then change the color of the line to green and show it again,
and then finally delete the line and show the canvas again (which is now blank).
The name of the element (my_line
) is used to refer to the element for all the
operations.
my_canvas = Canvas()
my_canvas['my_line'] = Line(-100, -100, 100, 100, color='red')
my_canvas.show()
clock.sleep(1000)
my_canvas['my_line'].color = 'green'
my_canvas.show()
clock.sleep(1000)
del my_canvas['my_line']
my_canvas.show()
You can also add an element without explicitly providing a name for it. In that
case, a name is generated automatically (e.g. stim0
).
my_canvas = Canvas()
my_canvas += FixDot()
my_canvas.show()
If you add a list of elements, they will be automatically grouped together, and you can refer to the entire group by name.
my_canvas = Canvas()
my_canvas['my_cross'] = [ Line(-100, 0, 100, 0), Line(0, -100, 0, 100)]
my_canvas.show()
To check whether a particular x,y
coordinate falls within the bounding
rectangle of an element, you can use in
:
my_mouse = Mouse(visible=True)
my_canvas = Canvas()
my_canvas['rect'] = Rect(-100, -100, 200, 200)
my_canvas.show()
button, (x, y), time = my_mouse.get_click()
if (x, y) in my_canvas['rect']:
print('Clicked in rectangle')
else:
print('Clicked outside of rectangle')
You can also get a list of the names of all elements that contain an x,y
coordinate, using the Canvas.elements_at()
function, documented below.
arrow(sx, sy, ex, ey, body_length=0.8, body_width=0.5, head_width=30, **style_args)
Draws an arrow. An arrow is a polygon consisting of 7 vertices, with an arrowhead pointing at (ex, ey).
Parameters
- sx: The X coordinate of the arrow's base.
- sy: The Y coordinate of the arrow's base.
- ex: The X coordinate of the arrow's tip.
- ey: The Y coordinate of the arrow's tip..
- body_length: Proportional length of the arrow body relative to the full arrow [0-1].
- body_width: Proportional width (thickness) of the arrow body relative to the full arrow [0-1].
- head_width: Width (thickness) of the arrow head in pixels.
circle(x, y, r, **style_args)
Draws a circle.
Parameters
- x: The center X coordinate of the circle.
- y: The center Y coordinate of the circle.
- r: The radius of the circle.
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
# Function interface
my_canvas.circle(100, 100, 50, fill=True, color='red')
# Element interface
my_canvas['my_circle'] = Circle(100, 100, 50, fill=True, color='red')
clear(*arglist, **kwdict)
Clears the canvas with the current background color. Note that it is generally faster to use a different canvas for each experimental display than to use a single canvas and repeatedly clear and redraw it.
Parameters
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
my_canvas.fixdot(color='green')
my_canvas.show()
clock.sleep(1000)
my_canvas.clear()
my_canvas.fixdot(color='red')
my_canvas.show()
copy(canvas)
Turns the current Canvas
into a copy of the passed Canvas
.
Warning:
Copying Canvas
objects can result in unpredictable behavior. In many
cases, a better solution is to recreate multiple Canvas
objects from
scratch, and/ or to use the element interface to update Canvas
elements individually.
Parameters
- canvas: The
Canvas
to copy.
Example
my_canvas = Canvas()
my_canvas.fixdot(x=100, color='green')
my_copied_canvas = Canvas()
my_copied_canvas.copy(my_canvas)
my_copied_canvas.fixdot(x=200, color="blue")
my_copied_canvas.show()
elements_at(x, y)
New in v3.2.0
Gets the names of elements that contain a
particular x, y
coordinate.
Parameters
- x: An X coordinate.
- y: A Y coordinate.
Returns
- A
list
of element names that contain the coordinatex, y
.
Example
# Create and show a canvas with two partly overlapping rectangles
my_canvas = Canvas()
my_canvas['right_rect'] = Rect(x=-200, y=-100, w=200, h=200, color='red')
my_canvas['left_rect'] = Rect(x=-100, y=-100, w=200, h=200, color='green')
my_canvas.show()
# Collect a mouse click and print the names of the elements that
# contain the clicked point
my_mouse = Mouse(visible=True)
button, pos, time = my_mouse.get_click()
if pos is not None:
x, y = pos
print('Clicked on elements: %s' % my_canvas.elements_at(x, y))
ellipse(x, y, w, h, **style_args)
Draws an ellipse.
Parameters
- x: The left X coordinate.
- y: The top Y coordinate.
- w: The width.
- h: The height.
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
# Function interface
my_canvas.ellipse(-10, -10, 20, 20, fill=True)
# Element interface
my_canvas['my_ellipse'] = Ellipse(-10, -10, 20, 20, fill=True)
fixdot(x=None, y=None, style='default', **style_args)
Draws a fixation dot. The default style is medium-open.
- 'large- filled' is a filled circle with a 16px radius.
- 'medium-filled' is a filled circle with an 8px radius.
- 'small-filled' is a filled circle with a 4px radius.
- 'large-open' is a filled circle with a 16px radius and a 2px hole.
- 'medium-open' is a filled circle with an 8px radius and a 2px hole.
- 'small-open' is a filled circle with a 4px radius and a 2px hole.
- 'large-cross' is 16px cross.
- 'medium-cross' is an 8px cross.
- 'small-cross' is a 4px cross.
Parameters
- x: The X coordinate of the dot center, or None to draw a horizontally centered dot.
- y: The Y coordinate of the dot center, or None to draw a vertically centered dot.
- style: The fixation-dot style. One of: default, large-filled, medium- filled, small-filled, large-open, medium-open, small-open, large- cross, medium-cross, or small-cross. default equals medium-open.
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
# Function interface
my_canvas.fixdot()
# Element interface
my_canvas['my_fixdot'] = FixDot()
gabor(x, y, orient, freq, env='gaussian', size=96, stdev=12, phase=0, col1='white', col2='black', bgmode='avg')
Draws a Gabor patch. Note: The exact rendering of the Gabor patch depends on the back-end.
Parameters
- x: The center X coordinate.
- y: The center Y coordinate.
- orient: Orientation in degrees [0 .. 360]. This refers to a clockwise rotation from a vertical.
- freq: Frequency in cycles/px of the sinusoid.
- env: The envelope that determines the shape of the patch. Can be "gaussian", "linear", "circular", or "rectangular".
- size: A size in pixels.
- stdev: Standard deviation in pixels of the gaussian. Only applicable to gaussian envelopes.
- phase: Phase of the sinusoid [0.0 .. 1.0].
- col1: A color for the peaks.
- col2: A color for the troughs. Note: The psycho back-end
ignores this
parameter and always uses the inverse of
col1
for the throughs. - bgmode: Specifies whether the background is the average of col1 and col2 ('avg', corresponding to a typical Gabor patch), or equal to col2 ('col2'), useful for blending into the background. Note: this parameter is ignored by the psycho backend, which uses increasing transparency for the background.
Example
my_canvas = Canvas()
# Function interface
my_canvas.gabor(100, 100, 45, .05)
# Element interface
my_canvas['my_gabor'] = Gabor(100, 100, 45, .05)
image(fname, center=True, x=None, y=None, scale=None, rotation=None)
Draws an image from file. This function does not look in the file pool, but takes an absolute path.
Parameters
- fname: The filename of the image. When using Python 2, this should be
either
unicode
or a utf-8-encodedstr
. When using Python 3, this should be eitherstr
or a utf-8-encodedbytes
. - center: A bool indicating whether coordinates indicate the center (True) or top-left (False).
- x: The X coordinate, or
None
to draw a horizontally centered image. - y: The Y coordinate, or
None
to draw a vertically centered image. - scale: The scaling factor of the image.
None
or 1 indicate the original size. 2.0 indicates a 200% zoom, etc. - rotation: The rotation of the image
None
or 0 indicate the original rotation. Positive values indicate a clockwise rotation in degrees.
Example
my_canvas = Canvas()
# Determine the absolute path:
path = exp.pool['image_in_pool.png']
# Function interface
my_canvas.image(path)
# Element interface
my_canvas['my_image'] = Image(path)
line(sx, sy, ex, ey, **style_args)
Draws a line.
Parameters
- sx: The left X coordinate.
- sy: The top Y coordinate.
- ex: The right X coordinate.
- ey: The bottom Y coordinate.
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
lower_to_bottom(element)
Lowers an element to the bottom, so that it is drawn first; that is, it becomes the background.
Parameters
- element: A sketchpad element, or its name.
noise_patch(x, y, env='gaussian', size=96, stdev=12, col1='white', col2='black', bgmode='avg')
Draws a patch of noise, with an envelope. The exact rendering of the noise patch depends on the back-end.
Parameters
- x: The center X coordinate.
- y: The center Y coordinate.
- env: The envelope that determines the shape of the patch. Can be "gaussian", "linear", "circular", or "rectangular".
- size: A size in pixels.
- stdev: Standard deviation in pixels of the gaussian. Only applicable to gaussian envelopes.
- col1: The first color.
- col2: The second color. Note: The psycho back-end ignores this
parameter
and always uses the inverse of
col1
. - bgmode: Specifies whether the background is the average of col1 and col2 ('avg', corresponding to a typical Gabor patch), or equal to col2 ('col2'), useful for blending into the background. Note: this parameter is ignored by the psycho backend, which uses increasing transparency for the background.
Example
my_canvas = Canvas()
# Function interface
my_canvas.noise_patch(100, 100, env='circular')
# Element interface
my_canvas['my_noise_patch'] = NoisePatch(100, 100, env='circular')
polygon(vertices, **style_args)
Draws a polygon that defined by a list of vertices. I.e. a shape of points connected by lines.
Parameters
- vertices: A list of tuples, where each tuple corresponds to a vertex. For example, [(100,100), (200,100), (100,200)] will draw a triangle.
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
n1 = 0,0
n2 = 100, 100
n3 = 0, 100
# Function interface
my_canvas.polygon([n1, n2, n3])
# Element interface
my_canvas['my_polygon'] = Polygon([n1, n2, n3])
prepare()
Finishes pending canvas operations (if any), so that a subsequent
call to [canvas.show] is extra fast. It's only necessary to call this
function if you have disabled auto_prepare
when initializing the
Canvas
.
raise_to_top(element)
Raises an element to the top, so that it is drawn last; that is, it becomes the foreground.
Parameters
- element: A sketchpad element, or its name.
rect(x, y, w, h, **style_args)
Draws a rectangle.
Parameters
- x: The left X coordinate.
- y: The top Y coordinate.
- w: The width.
- h: The height.
- **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
# Function interface
my_canvas.rect(-10, -10, 20, 20, fill=True)
# Element interface
my_canvas['my_rect'] = Rect(-10, -10, 20, 20, fill=True)
rename_element(old_name, new_name)
Renames an element.
show()
Shows, or 'flips', the canvas on the screen.
Returns
- A timestamp of the time at which the canvas actually appeared on
the screen, or a best guess if precise temporal information is not
available. For more information about timing, see .
Depending on the back-end the timestamp is an
int
or afloat
.
Example
my_canvas = Canvas()
my_canvas.fixdot()
t = my_canvas.show()
exp.set('time_fixdot', t)
text(text, center=True, x=None, y=None, max_width=None, **style_args)
Draws text.
Parameters
- text: A string of text. When using Python 2, this should be either
unicode
or a utf-8-encodedstr
. When using Python 3, this should be eitherstr
or a utf-8-encodedbytes
. - center: A bool indicating whether the coordinates reflect the center (
True
) or top-left (False
) of the text. - x: The X coordinate, or None to draw horizontally centered text.
- y: The Y coordinate, or None to draw vertically centered text.
- max_width: The maximum width of the text in pixels, before wrapping to a new line, or
None
to wrap at screen edge. - **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Example
my_canvas = Canvas()
# Function interface
my_canvas.text('Some text with <b>boldface</b> and <i>italics</i>')
# Element interface
my_canvas['my_text'] = Text('Some text with <b>boldface</b> and <i>italics</i>')
text_size(text, center=True, max_width=None, **style_args)
Determines the size of a text string in pixels.
Parameters
- text: A string of text.
- center: A bool indicating whether the coordinates reflect the center (
True
) or top-left (False
) of the text. - max_width: The maximum width of the text in pixels, before wrapping to a new line, or
None
to wrap at screen edge. - **style_args: Optional style keywords that specify the style of the current drawing operation. This does not affect subsequent drawing operations.
Returns
- A (width, height) tuple containing the dimensions of the text string.
Example
my_canvas = Canvas()
w, h = my_canvas.text_size('Some text')