Intro to PsychoPy#

Fork the repository for Intro to Psychopy.

Once you fork or clone the repository, you’ll see a file with the starter code. This is the file you will edit and add to as we work through the walkthrough. For reference, the code is reproduced below.

The starter code will show a blue circle for two seconds (2000 ms), then an orange circle for two seconds, and then exit out of the program.

from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough

#open a window
win = visual.Window([600,600],color="grey", units='pix', checkTiming=False) 

#create a blue circle
blue_circle = visual.Circle(win,lineColor="grey",fillColor="blue",size=[100,100])

#show the blue circle
#first, draw the blue circle to the back buffer of the window
#this means that the blue circle won't be displayed right away
blue_circle.draw()
#then "flip" the window to show what you just drew
win.flip()

#wait 2 seconds
core.wait(2.0)

win.close() #close the window
core.quit() #quit out of the program

Intro#

Let’s first go through each line of the code above and understand what each line does.

In the code, we:

  • create a new window to display stimuli in using psychopy’s Window function

  • create a (blue) circle stimulus using one of psychopy’s many visual stimuli classes

  • display that stimulus by executing the core display strategy in Psychopy

    • draw the stimulus to the “back” window buffer

    • flip the window to show what was just drawn

  • pause for 2 seconds using psychopy’s core functions for controlling timing

Drawing and Flipping Visual Stimuli

When you first use .draw() to draw a stimulus to the window, it is not displayed right away. Instead, psychopy allows us to draw as many visual stimuli to a particular display as we like, but does not update what is shown to participants until we use win.flip() to flip or refresh the window. This might seem overly complicated at first, but it turns out to be a really useful feature because it gives us a lot of precise control over when exactly a particular visual stimulus is shown (basically, drawing is “slow”, flipping is quick and can be timed to other things).

One way to visualize this is to imagine that the window has two layers, a front and a back. The front is what the participants see. When we use .draw() to draw a stimulus, we “paint” that stimulus to the back of the window, so it is not visible to participants. Then once we’ve drawn to our heart’s content, we flip the window over so the back is visible to participants.

Show an orange circle after the blue circle#

Next, let’s add a second trial where we show an orange circle.

from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough

#open a window
win = visual.Window([600,600],color="grey", units='pix', checkTiming=False) 

#create a blue circle
blue_circle = visual.Circle(win,lineColor="grey",fillColor="blue",size=[100,100])

#create an orange circle
orange_circle = visual.Circle(win,lineColor="grey",fillColor="orange",size=[100,100])

#show the blue circle
#first, draw the blue circle to the back buffer of the window
#this means that the blue circle won't be displayed right away
blue_circle.draw()
#then "flip" the window to show what you just drew
win.flip()

#wait 2 seconds
core.wait(2.0)

#draw the orange circle
orange_circle.draw()
win.flip()
core.wait(2.0)

win.close() #close the window
core.quit() #quit out of the program

Collect a Keyboard Response#

Next, let’s collect a keyboard response from participants. We want participants to press the key “b” if they see a blue circle, and “o” if they see an orange circle.

Tip

The key functions to accept keyboard input are event.getKeys() and event.waitKeys(). Look at how these functions are defined at the psychopy API web page or by typing help(function name), e.g., help(event.getKeys) after importing event

Note

getKeys checks if a certain key has been entered since the last call to getKeys, e.g., if an ‘s’ was pressed, event.getKeys(['s']) will become True. event.waitKeys() waits until a certain key (or any key) was pressed.

Below, we use event.waitKeys() to pause everything until a participant presses either ‘b’ or ‘o’. WE’ll use this code to replace the core.wait(2) line after each of our stimuli are shown. Then

key_pressed = event.waitKeys(keyList=['b','o']) # wait until the participant presses one of the keys from the key list

if key_pressed: # once they press one of those keys, print it out and flip the window (why?)
    print(key_pressed)
    win.flip()

The full code now looks like this:

from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough

#open a window
win = visual.Window([600,600],color="grey", units='pix', checkTiming=False) 

#create a blue circle
blue_circle = visual.Circle(win,lineColor="grey",fillColor="blue",size=[100,100])

#create an orange circle
orange_circle = visual.Circle(win,lineColor="grey",fillColor="orange",size=[100,100])

#show the blue circle
#first, draw the blue circle to the back buffer of the window
#this means that the blue circle won't be displayed right away
blue_circle.draw()
#then "flip" the window to show what you just drew
win.flip()

#wait until the participant presses one of the keys from the key list
key_pressed = event.waitKeys(keyList=['b','o'])
#once they press one of those keys, print it out and flip the window (why?)
if key_pressed:
    print(key_pressed)
    win.flip()

#wait one second after the response
core.wait(1)

#show the orange circle
#first, draw the blue circle to the back buffer of the window
#this means that the blue circle won't be displayed right away
orange_circle.draw()
#then "flip" the window to show what you just drew
win.flip()

#wait until the participant presses one of the keys from the key list
key_pressed = event.waitKeys(keyList=['b','o'])
#once they press one of those keys, print it out and flip the window (why?)
if key_pressed:
    print(key_pressed)
    win.flip()

win.close() #close the window
core.quit() #quit out of the program

Changing properties of stimuli#

Once we have created a stimulus, we can update its properties very flexibly.

For example, for our circle stimuli, we can update the color of the object very easily.

#update the color of the blue_circle to purple, then re-draw and flip
blue_circle.color = "purple"
blue_circle.draw() #not a blue circle anymore!
win.flip()

Using for-loops to present trial lists#

Currently our code is kind of cumbersome: we have a lot of repetitive elements. Especially if we want to show a lot of trials, copy-pasting the same thing many times seems like a suboptimal strategy for creating our full experiment.

Instead, we can use a for-loop in which we cycle through each trial we want to display to make our experiment much more compact.

from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough

#open a window
win = visual.Window([600,600],color="grey", units='pix', checkTiming=False) 

#create a general circle
circle = visual.Circle(win,lineColor="grey",fillColor="blue",size=[100,100])

# trial list
color_trials = ["blue","orange"]

#loop through the trial list
for current_color in color_trials:
    #update the current color
    circle.color = current_color
    #draw the circle
    circle.draw()
    #flip the window
    win.flip()

    #wait until the participant presses one of the keys from the key list
    key_pressed = event.waitKeys(keyList=['b','o'])
    #once they press one of those keys, print it out and flip the window (why?)
    if key_pressed:
        print(key_pressed)
        win.flip()

    #wait one second after the response
    core.wait(1)

Add an instruction#

To add one more element, let’s add an instruction for each trial.

Below each circle, we want to show the following instruction: “Press b if the circle is blue and o if the circle is orange.”

We can accomplish this using the visual.TextStim() class in psychopy.

Tip

Notice in the code below that we can draw multiple stimuli to the screen. In fact, we can draw as many as we like! This is really useful for creating layered/ more complex visual displays. Just bear in mind that items are drawn in order (so sometimes an item can obscure another item!).

#create the instruction text
instruction_text = "Press b if the circle is blue and o if the circle is orange."
instruction = visual.TextStim(win, text = instruction_text, pos = (-100,0))

Now let’s add it to the code so far, making sure to draw it on each trial.

from psychopy import visual, event, core # import the bits of PsychoPy we'll need for this walkthrough

#open a window
win = visual.Window([600,600],color="grey", units='pix', checkTiming=False) 

#create a general circle
circle = visual.Circle(win,lineColor="grey",fillColor="blue",size=[100,100])

#create the instruction text
instruction_text = "Press b if the circle is blue and o if the circle is orange."
instruction = visual.TextStim(win, text = instruction_text,color="black", pos = (0,-100))

# trial list
color_trials = ["blue","orange"]

#loop through the trial list
for current_color in color_trials:
    #update the current color
    circle.color = current_color
    #draw the circle
    circle.draw()
    #draw the instruction
    instruction.draw()
    #flip the window
    win.flip()

    #wait until the participant presses one of the keys from the key list
    key_pressed = event.waitKeys(keyList=['b','o'])
    #once they press one of those keys, print it out and flip the window (why?)
    if key_pressed:
        print(key_pressed)
        win.flip()

    #wait one second after the response
    core.wait(1)

Explore on your own!#

Tip

Each time you make a change, re-run your code to see if it worked! The more changes you make before testing, the more chances there are for an error to slip in, and then it can get harder to figure out why something isn’t working. Running your code frequently after small changes is a good way to get comfortable editing code as you start to get familiar with the concepts and syntax.

  1. Change the color(s) of the circles.

  2. Change the size of the circles.

  3. Change which keyboard keys can be used to respond.

  4. Change how long the stimuli are shown on the screen.

  5. Can you figure out how to provide contingent feedback to people’s responses? Provide contingent feedback to participants after each trial:

  • If they respond correctly (e.g., “b” for blue), present text reading: “That was correct!”

  • If they respond incorrectly (e.g., “o” for blue), present text reading: “Sorry, that was incorrect!”

  1. The repository includes some Pokemon images. Can you figure out how to display them?

    Tip

    Check out the visual.ImageStim() class