TrialHandler – a PsychoPy tutorial

In this tutorial you will get to know how to use the PsychoPy function TrialHandler to create trials and correct responses to your targets in these trials. PsychoPy is an application for creating experiments for Psychology experiments. The application is written in Python, an easy programming language to learn. You can learn more about PsychoPy in my two previous posts (Free and Useful software – PsychoPy and Python apps and libraries…”).

TrialHandler Tutorial

We start by importing data from PsychoPy. In data we found the routine we want to use (e.g., TrialHandler):

Prepatory work


from psychopy import data

We start with a simple list of trials. In this example, the subjects are going to categorize digits as odd or even (like in a cross-modal oddball task).
We create the target list with digits from 1-8.


visual_targets = [digit for digit in xrange(1,9)]

Note that, you can create the same list with a for-loop:


visual_targets = []

for digit in xrange(1,9):
    visual_targets.append(digit)

Lets continue with creating a new list containing a dictionary for each trial. Each dictionairy (i.e., trial) contain the keys ‘Target’ and ‘CorrectResponse’. This is were we store each Target and its correct response. In the example the response keys can be ‘z’ and ‘x’ (odd and even, respectively)
We start to loop through our list of targets,


targets_responses = []

for target in visual_targets:

    if target %2 == 0:
        correct_response = 'x'

    else:
        correct_response = 'z'

    targets_responses.append({'Target':target, 'CorrectResponse':correct_response})

TrialHandler

Now that we have our list with the targets and correct responses we can use that list with PsychoPy’s TrialHandler. In our example we are going randomize our targets and present them 160 times


trials = data.TrialHandler(targets_responses,20, method='random')

We also want to record what the subjects responded, if a correct response (Accuracy) was given


trials.data.addDataType('Response')
trials.data.addDataType('Accuracy')

Window, stimuli, & timing

When we run the experiment we can just do a for-loop. However, we are going to create a window first (we need to somewhere to present our targets).
Therefore, we need to import visual and create a window. Typically, you would import everything in the beginning of your script.


from psychopy import visual

experiment_window = visual.Window(size=(800,600),winType='pyglet',fullscr=False, 
    screen=0, monitor='testMonitor',
    color="black", colorSpace='rgb')

We also need to create an object for the text stimuli. We use the routine TextStim for this:


screen_text = visual.TextStim(experiment_window,text=None,
    alignHoriz="center", color = 'white')

We are almost there… We need some timing for the stimuli. We use Clock from core for this and create a trial time. Furthermore, we use event to collect responses from the keyboard.


from psychopy import core, event
trial_timer = core.Clock()

Presenting stimuli

We are now ready to start our experiment loop. TrialHandler makes it possible to loop through each trial we created with it.

At the beginning of the loop we with setting the current_time to zero, trial_still_running to True and reset the trial_timer. This is done so that we can present our target for 400ms after a 400ms fixation cross. The target is followed by a response window of 1000ms in which the fixation cross is presented again.  In the loop, the response will be collected in a list (i.e.,, “responded”). The first item of this list is controlled against the correct response (i.e., trial[‘CorrectResponse’]) for the trial.


for trial in trials:
    current_time = 0
    trial_still_running = True
    trial_timer.reset()

    while trial_still_running:
        current_time = trial_timer.getTime()

        if current_time <=.4:
            screen_text.setText('+')
            screen_text.draw()

        if current_time >= .4 and current_time <=.8:
            screen_text.setText(trial['Target'])
            screen_text.draw()

        if current_time >= .8 and current_time <=1.8:
            screen_text.setText('+')
            screen_text.draw()
            responded = event.getKeys()

        if responded:
            if trial['CorrectResponse'] == responded[0]:
                accuracy = 1

            else: accuracy = 0

        if current_time >= 1.8:
            if not responded:
                accuracy = 0

            trial_still_running = False

       experiment_window.flip()

We end by closing the window and quitting:


experiment_window.close()
core.quit()

Data also contains routines for saving data but I have not included that in the above script. However, if you want to store your data add the following code at the end of the for-loop:


trials.data.add('Accuracy', accuracy)
trials.data.add('Response', responded[0])

It is also pretty easy to save your data as an Excel-fie (e.g., .csv or .xlsx)

trials.saveAsExcel(fileName='data.csv',
                  sheetName = 'rawData',
                  stimOut=[], 
                  dataOut=['all_raw'])

Note that, if timing is important for your experiment it is better to control stimulus timing by present them for a specified number of frames instead (see here for more information).

If you want to see a more complete example of a task written in Python and PsychoPy look at my Sustained Attention to Response Task (SART). In the SART I randomize the stimuli with my method, however. That is, if you need randomization with constraints you might need to do that prior to using TrialHandler and, also, use “method=’sequential’” instead.

Finally, I uploaded the complete script, including data saving, to pastebin. Hopefully, this tutorial helped you  to understand how to use TrialHandler. Please let me know what you think or if something does not work as expected.

 

The post TrialHandler – a PsychoPy tutorial appeared first on Erik Marsja.