Drawing—dots
Objectives
- Be able to create and manipulate stimuli formed from a number of individual elements.
Patterns formed from a number of small elements (“dots”, typically circles, Gaussians, or squares) are versatile stimuli that are frequently used in vision research.
In psychopy, we typically create dot stimuli using ElementArrayStim.
The key point about ElementArrayStim is that many of its parameters accept a list, rather than only a single value.
This allows us to conveniently create a stimulus from many individual elements.
The xys is a critical parameter that specifies the position of each element.
For example, we can draw a set of randomly-positioned dots by:
import random
import psychopy.visual
import psychopy.event
win = psychopy.visual.Window(
size=[400, 400],
units="pix",
fullscr=False
)
n_dots = 200
dot_xys = []
for dot in range(n_dots):
dot_x = random.uniform(-200, 200)
dot_y = random.uniform(-200, 200)
dot_xys.append([dot_x, dot_y])
dot_stim = psychopy.visual.ElementArrayStim(
win=win,
units="pix",
nElements=n_dots,
elementTex=None,
elementMask="circle",
xys=dot_xys,
sizes=10
)
dot_stim.draw()
win.flip()
psychopy.event.waitKeys()
win.close()
There are a few things to note about the code above:
- We specify
xysas a list of lists; the “outer” list has a number of elements that matches the number of dots. Each element is itself a list, with two elements—the x and y location of that particular dot. - Note the use of
elementTexhere. By setting it to the special Python valueNone, we are telling psychopy that we want the “texture” of each dot to just be uniform white. Then, by settingelementMaskto"circle", we are able to define the shape of each individual dot. - Notice how the size of the dots is specified by the parameter
sizes, rather than the typicalsize. That means that we could provide a list with a length corresponding to the number of dots, with each element of the list specifying the size of that particular dot. By just giving a single number here, we are telling psychopy to use this value for all of the dots.
The ElementArrayStim doesn’t just have to be used for shape-based dots, though.
By setting the elementTex and elementMask parameters, we have great flexibility in what comprises our stimulus.
For example, we could use lots of little gratings:
import random
import psychopy.visual
import psychopy.event
win = psychopy.visual.Window(
size=[400, 400],
units="pix",
fullscr=False
)
n_dots = 200
dot_xys = []
for dot in range(n_dots):
dot_x = random.uniform(-200, 200)
dot_y = random.uniform(-200, 200)
dot_xys.append([dot_x, dot_y])
dot_stim = psychopy.visual.ElementArrayStim(
win=win,
units="pix",
nElements=n_dots,
elementTex="sin",
elementMask="gauss",
sfs=5.0 / 2.5,
xys=dot_xys,
sizes=20
)
dot_stim.draw()
win.flip()
psychopy.event.waitKeys()
win.close()
Tip
In ElementArrayStim, the sfs parameter when units="pix" is the number of cycles per element, rather than the number of cycles per pixel.
Perhaps with random orientations:
import random
import psychopy.visual
import psychopy.event
win = psychopy.visual.Window(
size=[400, 400],
units="pix",
fullscr=False
)
n_dots = 200
dot_xys = []
dot_oris = []
for dot in range(n_dots):
dot_x = random.uniform(-200, 200)
dot_y = random.uniform(-200, 200)
dot_xys.append([dot_x, dot_y])
dot_oris.append(random.uniform(0, 180))
dot_stim = psychopy.visual.ElementArrayStim(
win=win,
units="pix",
nElements=n_dots,
elementTex="sin",
elementMask="gauss",
sfs=5.0 / 2.5,
xys=dot_xys,
sizes=20,
oris=dot_oris
)
dot_stim.draw()
win.flip()
psychopy.event.waitKeys()
win.close()