Psychopy
A Tutorial for Machine-Motivated Human Vision
Step # 1: Download and Install Psychopy
Go to the following link and download the standalone installer for either Windows or macOS. https://github.com/psychopy/psychopy/releases
- Run the Installer and carefully read the agreement before accepting it. (lol)
- Linux users can follow the installation using Anaconda/pip guide on the official website: https://www.psychopy.org/download.html
Step # 2: Open Psychopy and create a new project
You can create a new project by clicking on File -> New
The blank project starts with a single routine called trial
Step # 3: Decide what experiment you are going to run
Here we will create an experiment where the participants will perform a match-to-sample task. We have a dataset of dog images (Download here). Images from this dataset will be randomly selected followed by two other random images from the same dataset. The participants will use the left or right keypresses to select which of the two images shown later resembles the original image more. (Note: the dataset you will see in class will be different from the one available here)
Step # 4: Create a rough flow of your experiment on paper
Here, we may want to present all the images from our dataset twice to a subject in batches of eight images. Below is a rough paper flow chart for this experiment.
For the sake of this tutorial, we will call an individual presentation of an image a ‘presentation’, a batch of eight images a ‘trial’, and a whole run of the dataset a ‘repetition’. These are not standard terms but just the format used in my lab. An experiment may also contain different ‘blocks’. For example, the first part of an experiment may teach the task to the participants followed by a test block which is analyzed.
Step # 5: Understanding Routines and Components
Routines are execution units in psychopy. At one moment, your experiment stays in one routine. A routine could be a screen with a welcome message, a data collection form for your subjects, or a stimulus-response action.
Components are elements in psychopy that can be added to a routine. A text box, an image, a button, or a keypress are all examples of components that can be added to a routine. We will start by creating an ‘instruction’ page routine that would explain the contents of the experiment to the participant.
Inside the Psychopy builder, select “insert routine” from the flow panel and add it behind the existing ‘trial’ routine.
From the components panel, select text from the stimuli section and write a brief prompt. To keep this instruction text on the screen until a keypress is made, change the duration value of the text to blank. This way the text would stay until the end of the routine.
Next, we will add a ‘keyboard’ component from the responses section which would end the routine when any key is pressed. To achieve that, remove all the keys from the allowed keys option.
You can try to run your experiment now. When you click run, you would realize that we forgot to save the experiment. Make sure you create a separate folder for the experiment before saving it.
You will get a window with your text that will close as soon as you press a key.
Step # 6: Initialize some variables
There are two ways to create variables available in the custom section of the components panel.
- The code component
The code component can be used to add your own code to your routine. Inside the code component, you can write code that would execute at different times in your experiment.
Here, we can initialize some variables by adding them to the ‘Begin Experiment’ tab.
curr_stim = ‘’
curr_left = ‘’
curr_right = ‘’all_images = [os.path.join(os.getcwd(), \
expInfo[‘image_directory’],i) \
for i in os.listdir(expInfo[‘image_directory’])]stim_images = all_images.copy()
num_images = len(all_images)
Since we use the ‘os’ library of python, we can import that and other packages we may use in the ‘Before Experiment’ tab.
import os
import numpy as np
We are using the os library to get a list of all images in the image directory. In this particular case, we add the image directory information to the experiment information option in the project settings.
2. The variable component
Variable component allows us to create python variables that can be used throughout the experiment. Variables can be assigned a default value for the start of the experiment, the routine, or a frame. One advantage of using the variable component is that it offers better visibility during experiment design. We will use this component to create variables to store values for the experiment parameters like the number of images per trial, the number of repetitions of the entire dataset, and the number of trials.
Note above that the variable num_trial relies on the variable num_stimuli_per_trial and num_images. Both these variables need to be defined before defining num_trials. The order in which you add components to the routine is how they will execute. The components can be moved up or down by right-clicking on them.
Step # 7: Create the main routine (Image presentation + Image choice) (This should have been multiple steps but I had already made the outline OTL)
Now that we have created the instruction routine and initialized some variables that we will use, it is time to create the main routine which will contain the actual experiment.
7.1) Let’s remove the trial routine by right-clicking and selecting remove. We will then add a new routine called ‘Presentation’ using the ‘Insert Routine’ option after the ‘Instruction’ routine.
7.2) Use the Image component from the stimuli and add three Image components to the routine. Let’s call them ‘stimuli’, ‘image_left’, and ‘image_right’.
7.3) Change the start times and durations of these three images.
Change the duration of ‘stimuli’ to 0.2.
Change the start time of both image_left and image_right to 0.4 and erase the duration entry to leave it blank.
7.4) Change the Image text box for the three image components to the variable names we defined earlier: $curr_stim, $curr_left, $curr_right, and change the constant option on the right to “set every repeat”.
Note, that the symbol $ is used to refer to code i.e., instead of setting a constant value, you can use the dollar sign followed by a code snippet, which in this case are the variable names.
7.5) We will now resize the images and change their locations. Go to the Layout tab in the properties of image components and change the Size [w,h] of all three images to (0.25, 0.25).
For the image_left and image_right components, set the Position [x,y] values to (-0.5,0) and (0.5, 0) respectively.
7.6) We will now add a keyboard component to record participant responses to the images. Use the following values for the properties:
7.7) Lastly, we will add a code block that will allow us to set the curr_stim, curr_left, and curr_right variables at the beginning of the presentation routine. We will add a small python code in the ‘Begin Routine’ tab of a code component.
rand_ids = np.random.choice(range(len(all_images)),
2, replace=False)
stim_id = np.random.randint(len(stim_images))
curr_stim = stim_images[stim_id]
curr_left = all_images[rand_ids[0]]
curr_right = all_images[rand_ids[1]]
We are randomly selecting three images from our dataset and assigning them to curr_stim, curr_left, and curr_right variables. Note that we select the image for the stimuli component separate from the left and right options. Why do we do this? Why do we do anything?
To wrap this step up, right-click on the code component and select the ‘move to the top’ option otherwise the image components will try to access their variables before they get assigned correct paths.
This is also a good moment to download the image dataset from earlier into your project folder and rename it to ‘images’.
Step # 8: Create the loops
The major part of the experiment is done. We will now insert some loops into our experiment. Recall, the hand-drawn figure from earlier.
Following the flowchart above, we will add a first loop that would control the number of images per trial. We will achieve this using the ‘Insert Loop’ option in the Flow panel.
We will change the nReps value and set it to the num_stimuli_per_trial variable we created earlier and rename this loop to presentations.
Next, we will add another loop on top of this to control the number of trials per repetition. nReps → num_trials
Finally, we will add one last loop to control the number of repetitions of the entire dataset. nReps → num_reps
For this experiment to work correctly, we need to make sure that the same image is not used more than once per repetition. This can be achieved by removing the image from the stim_images array after every presentation routine. This way, once all images are used as stimuli, stim_images would become empty and we can set it equal to the all_images array before starting a new repetition. We need to make sure that once stim_images is empty, our code does not try to access it and breaks out of the presentations loop to starts a new repetition.
We will achieve the desired behavior using the following two steps:
- We add the following code to our code component inside the ‘presentation’ routine under the ‘End Routine’ tab:
stim_images.pop(stim_id)
if not stim_images:
presentations.finished=True
Setting presentations.finished =True allows us to end the presentation loop early on.
To reset the stim_images variable, we will create a new routine at the beginning of every rep.
Inside the begin_rep routine, we will add a code component and add the following line to the ‘Begin Routine’ tab:
stim_images = all_images.copy()
Step # 9: Add intervals using existing templates
Our experiment is pretty much ready. But currently, there are no intervals. Intervals are our primary reason for using a variable number of images per trial. We will add two interval routines to our flow: a short interval between each presentation inside the presentations loop and a longer interval between trials.
We can use an existing routine template for this. From insert routine, select the routine template “Basic: fixed_interval” and name it ‘presentation_interval’. We will place it after the presentation routine inside the presentations loop.
Inside this template is a single text box with a ‘+’ symbol that appears for 0.5s as a fixation point.
Similarly, we will add another routine of the same template and call it the ‘trial_interval’. This would be placed after the presentations loop inside the trials loop. We will also change the duration of this interval to 1s by changing the duration of the text box inside it.
Step # 10: Add an experiment end routine
End routine is where you can either collect feedback or simply give participants an exit prompt and tell them how to close the experiment.
We will create a blank routine and add it at the very end of our flow chart.
Inside this routine, we will add a text box component with a blank duration. Psychopy experiments can be closed at any time by pressing escape. So, we will give that instruction in the exit prompt.
Step # 11: Select what (not) to save
Viola! Our experiment is ready to run. One last thing to consider is what data we want to collect from our experiment. Psychopy, by default, saves the onset times and offset times of all components. This includes every little text box that you may have created along the line. We can turn this off my right-clicking each component and unchecking the “save onset/offset time” checkbox under the data tab.
Psychopy, also saves the subject responses by default. In the experiment above, all the left and right responses that the participants give are saved.
What psychopy doesn’t save by default is the stimuli content information. So, in our case, the image ids of the images being randomly selected are actually lost which can make data analysis difficult, if not pointless. Therefore, it is very important to make sure that you check the data your experiment is saving. Any psychopy variable can be added to the saved data using the thisExp.addData() function.
To add the image paths for the stimuli, image_left and image_right for each image presentation, we will add the following three lines to the ‘End Routine’ tab in the code component of the presentation routine.
thisExp.addData(‘curr_stim’, curr_stim)
thisExp.addData(‘curr_left’, curr_left)
thisExp.addData(‘curr_right’, curr_right)stim_images.pop(stim_id)
if not stim_images:
presentations.finished=True
There are many many things that this tutorial did not cover but luckily Psychopy has a huge community support. There are entire semester length courses on youtube for psychopy. You can find a lot of help on the following links: