OpenSesame videos
Python videos
Supported by Supported by

Looping and independent variables

The loop item has two important functions:

  • It runs another item multiple times.
  • It is where you usually define your independent variables; that is, the variables that you manipulate in your experiment.

The item to run

A loop is always connected to a single other item: the item to run. You select the item to run in the box labeled "Run". In most cases, the item to run is a sequence, which runs multiple items sequentially.

Two common sequence-loop structures are:

  • If a sequence corresponds to a single trial (by convention called trial_sequence), then a loop that is connected to this sequence corresponds to multiple trials, or a block (by convention called block_loop).
  • If a sequence corresponds to a block of trials followed by a feedback display (by convention called block_sequence), then a loop that is connected to this sequence corresponds to multiple blocks, or a complete experimental session (by convention called experimental_loop).

Defining independent variables

The loop table is a powerful-yet-simple way to define independent variables. Every column in the table corresponds to a variable; every row corresponds to a cycle, that is, a level of the variable. For example, a simple loop with one variable (animal) that has two cycles ("cat" and "dog") looks like this:

animal
cat
dog

The loop has a few important options:

Repeat indicates how often each cycle should be executed. In the example above, repeat is set to 2, which means that trial_sequence is called twice while the variable animal has the value "cat", and twice while animal has the value "dog" (so four times in total).

Order indicates whether cycles should be executed sequentially or in random order. Randomization is complete, in the sense that the complete list of number-of-cycles × repeat trials is randomized.

Reading independent variables from file

If you want to read independent variables from file, rather than entering them into the loop table, you can do so as follows:

  • Set Source to file.
  • Select an Excel (.xlsx) or CSV (.csv) file in the File entry.

The source file follows the same conventions as the loop table; that is, each column corresponds to a variable, and each row corresponds to a cycle.

CSV files are expected to be in the following format:

  • plain-text
  • comma-separated
  • double-quoted (literal double-quotes are escaped with backward slashes)
  • UTF-8 encoded

Breaking the loop

If you want to break the loop before all cycles have been executed, you can specify a break-if statement. This break-if statement follows the same syntax as other if statements, as described on:

For example, the following break-if statement would break the loop as soon as a correct response is given:

[correct] = 1

The Evaluate on first cycle option indicates whether the break-if statement should be evaluated before the first cycle, in which case no cycles may be executed at all, or only before the second cycle, in which case at least one cycle is always executed.

Generating a full-factorial design

By clicking on the Full-factorial design you open a wizard that allows you to easily generate a full-factorial design, that is, a design in which each combination of factors occurs.

Pseudorandomization

You can add constraints for pseudorandomization to the script of the loop item. (Currently, this is not possible through the GUI.)

Example: Make sure that repetitions of the same word (given by the word variable) are separated by at least 4 cycles:

constrain word mindist=4

Example: Make sure that the same word is not repeated:

constrain word maxrep=1

constrain commands must come after setcycle commands.

Advanced loop operations

Commands for advanced loop operations must come after constrain and setcycle commands.

fullfactorial

The fullfactorial instruction treats the loop table as the input for a full-factorial design. For example, the following loop table:

cue duration
left 0
right 100
200

Would result in:

cue duration
left 0
left 100
left 200
right 0
right 100
right 200

shuffle

shuffle without argument randomizes the entire table. When a column name is specified (shuffle cue), only that column is randomized.

shuffle_horiz

shuffle_horiz shuffles all columns horizontally. When multiple columns are specified, only those columns are shuffled horizontally.

For example, when shuffle_horiz word1 word2 is applied to the following table:

word1 word2 word3
cat dog bunny
cat dog bunny
cat dog bunny

The result could be (i.e. values are randomly swapped between word1 and word2, but not word3):

word1 word2 word3
dog cat bunny
dog cat bunny
cat dog bunny

slice

slice [from] [to] selects a slice from the loop. It requires a start and an end index, where 0 is the first row, and negative values are counted from the end backwards. (Just like list slicing in Python, in other words.)

For example, when slice 1 -1 is applied to the following table:

word
cat
dog
bunny
horse

The result would be:

word
dog
bunny

sort

sort [column] sorts a single column, without changing any of the other columns.

sortby

sortby [column] sorts the entire table by a single column.

reverse

reverse reverses the order of the entire table. If a column name is specified (e.g. reverse word), only that column is reversed, without changing any of the other columns.

roll

roll [value] rolls the entire table forward (for positive values) or backward (for negative values). If a column name is specified (e.g. roll 1 word), only that column is rolled, without changing any of the other columns.

For example, if roll 1 is applied to the following table:

word
cat
dog
bunny
horse

The result would be:

word
horse
cat
dog
bunny

weight

weight [column] repeats each row by a weighting value specified in a column.

For example, if weight w is applied to the following table:

word w
cat 0
dog 0
bunny 2
horse 1

The result would be:

word w
bunny 2
bunny 2
horse 1

Previewing the loop

If you have specified constraints, or have used advanced loop operations, then it is a good idea to check that the result is as expected. To do so, you can generate a preview of the loop table as it will be (or could be, in case of randomization) when you run the experiment.

To generate a preview, click on the Preview button.

Accessing the loop table in Python inline script

The original loop table, as you see it in the OpenSesame user interface, is a DataMatrix object called dm, and is a property of the loop item.

This original loop table is usually transformed in various ways; for example, the order of the rows can be randomized, and rows can be repeated multiple times. The transformed loop is also a DataMatrix object, and is called live_dm. live_dm is created just before the loop is executed (i.e. during the run phase of the loop).

Finally, the current row is stored as the experimental variable live_row. That is, live_row indicates the currently active row of live_dm.

So let's say that we have a loop called block_loop. We could then access the loop table in a Python inline script as follows:

print('The original loop table:')
print(items['block_loop'].dm)

print('The transformed loop table:')
print(items['block_loop'].live_dm)

print('The current row:')
print(items['block_loop'].live_dm[var.live_row])

DataMatrix objects are powerful structures for working with tabular data. For more information, see:

Supported by Supported by