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
xys
as 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
elementTex
here. 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 settingelementMask
to"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()