Flow control¶
This part of the library provides components that control the sequence of events during the experiment. It is thus responsible for the flow of Components throughout the experiment. For example, a flow.Sequence()
groups several components together to be run sequentially, a flow.Loop()
repeats single components, and a flow.Parallel()
runs multiple components in parallel.
Sequence¶
-
class
flow.
Sequence
([options])¶ A
flow.Sequence()
runs a group of components one after another. These can be any type of component – screens or other stimuli, and even other sequences or loops.A typical experiment will often, on the highest, most coarse level, consist of a single sequence that encompasses the entirety of the experiment – instructions, experimental task, and debriefing – and runs it in sequence.
Sequences are, however, also useful on a much more granular level – for example, a single trial can be built as a sequence of an inter-stimulus interval, a fixation dot, and the stimulus itself.
-
flow.Sequence.options.
content
¶ List of components to run in sequence (
[]
)When a
flow.Sequence()
is constructed, the most important option is the content, which is a list of ‘sub-components’ that the sequence is comprised of. A basic example might be the following [1]:const proclaimers = new lab.flow.Sequence({ content: [ new lab.html.Screen({ content: 'And', timeout: 500 }), new lab.html.Screen({ content: 'I', timeout: 500 }), new lab.html.Screen({ content: 'will', timeout: 500 }), new lab.html.Screen({ content: 'walk', timeout: 500 }), new lab.html.Screen({ content: 'five', timeout: 500 }), new lab.html.Screen({ content: 'hun-', timeout: 500 }), new lab.html.Screen({ content: '-dred', timeout: 500 }), new lab.html.Screen({ content: 'miles', timeout: 500 }), ], }) proclaimers.run()
When the sequence is prepared or run, the constituent parts are prepared and run in sequence.
-
flow.Sequence.options.
shuffle
¶ Run the content components in random order (
false
)If this option is set to
true
, thecontent
of the sequence is shuffled during the prepare phase.
-
flow.Sequence.options.
handMeDowns
¶ List of options passed to nested components (
['datastore', 'el', 'debug']
)The options specified as
handMeDowns
are transferred to nested components during the prepare phase. This option is largely for convenience, and designed to decrease the amount of repetition when all nested components behave similarly – typically, nested components share the same data storage and output element, so these are passed on by default. Similarly, thedebug
mode is easiest to set on the topmost component, and will automatically propagate to include all other components.
-
Loop¶
-
class
flow.
Loop
([options])¶ A
flow.Loop()
repeats the same (single)template
component, while varyingparameters
between repetitions. Keeping with our example above:const template = new lab.html.Screen({ content: '${ parameters.lyrics }', // parameters substituted ... timeout: '${ parameters.beats * 600 }', // ... during preparation }) const spandauBallet = new lab.flow.Loop({ template: template, templateParameters: [ /* ... */ { lyrics: 'So true, funny how it seems', beats: 7 }, { lyrics: 'Always in time, but never in line for dreams', beats: 10 }, { lyrics: 'Head over heels when toe to toe', beats: 8 }, { lyrics: 'This is the sound of my soul', beats: 8 }, /* ... */ ] })
In many cases, the template will not be a single
html.Screen()
, but rather aflow.Sequence()
, so that multiple screens can be repeated on each iteration.-
flow.Loop.options.
template
¶ Content for each repetition of the loop.
There are several ways in which this option can be used:
- First it can be a single component of any type, an
html.Screen()
, (most likely) aflow.Sequence()
or even anotherflow.Loop()
. This component will becloned
for each iteration, and theparameters
substituted on each copy so that the repetitions can differ from another. - Second, it can be a function that creates and returns the component for each iteration. This function will receive each set of
templateParameters
in turn as a first argument (and, optionally, the index as a second argument, and the loop component itself as a third). The advantage of this method is a greater flexibility: Additional logic can be used at every step to customize every iteration.
- First it can be a single component of any type, an
-
flow.Loop.options.
templateParameters
¶ Array of parameter sets for each individual repetition (
[]
).This option defines the parameters for every repetition of the
template
. Each individual set of parameters is defined as an object with name/value pairs, and these objects are combined to an array:const stroopTrials = [ { color: 'red', word: 'red' }, { color: 'red', word: 'blue' }, /* ... */ ] const stroopTask = new lab.flow.Loop({ template: /* ... */, templateParameters: stroopTrials, })
-
flow.Loop.options.sample.
n
¶ The number of samples to draw from the
templateParameters
. If not specified, the number of samples defaults to the number of available parameter sets.Thus, in
sequential
,draw
anddraw-shuffle
mode
, leaving this option unset ensures that all parameter sets are used.
-
flow.Loop.options.sample.
mode
¶ How to sample from the iterations while constructing the loop. Several distinct modes are available (the default is
draw-shuffle
):sequential
: Run through the parameter sets in order. If all parameter sets have been run through, but more samples are required, re-start from the top.draw
: Sample from all parameter sets without replacement. When all sets have been drawn, start over.draw-shuffle
: Likedraw
, but shuffle the result when oversampling.draw-replace
: Sample from the parameter sets with replacement.
The
draw
anddraw-shuffle
modes only differ when the number of samples,n
exceeds the number of available parameter sets. In this case, thedraw
algorithm will lead to blocks of shuffled parameter sets. For example, given three parameter sets[1, 2, 3]
, over-sampling five sets might lead to a resulting order of[2, 3, 1, 2, 1]
(notice that all sets are exhausted before the first repetition occurs). Thedraw-shuffle
mode adds a shuffle step after sampling that breaks this restiction (which might lead to the result of[2, 3, 3, 2, 1]
). Thus indraw-shuffle
mode, the block structure is broken up, but the frequency of parameter sets will be roughly equal.
-
flow.Loop.options.
handMeDowns
¶ Options to pass to subordinate components (see
flow.Sequence()
).
-
Parallel¶
-
class
flow.
Parallel
([options])¶ A
flow.Parallel()
component runs other components concurrently, in that they are started together. Browser engines do not currently support literally parallel processing, but an effort has been made to approximate parallel processing as closely as possible.-
flow.Parallel.options.
content
¶ List of components to run in parallel (
[]
)
-
flow.Parallel.options.
mode
¶ How to react to nested elements ending (
'race'
)If this option is set to
'race'
, the entireflow.Parallel()
component ends as soon as the first nested component ends. In this case, any remaining components are shut down automatically (by callingend()
). If the mode is set to'all'
, it waits until all nested items have ended by themselves.
-
flow.Parallel.options.
handMeDowns
¶ Options passed to nested elements (see
flow.Sequence()
).
-
[1] | In apology to our British colleagues: This is, obviously, a grossly distorted version of the classic anthem: According to XKCD, the song has 131.9 beats per minute; the appropriate adjustment, as well as the Scottish accent, are left as an exercise for our esteemed readers. We hereby also pledge to award special prizes to any colleagues who use the library for interdepartmental karaoke (video proof required). |