Block sequence is the organizational component of the Procedure, defining (1) which individual blocks are presented, (2) to which participants each block is presented, and (3) in what order the blocks are presented to those participants.
Block sequence enables the realization of complex study designs involving between-subjects manipulation, randomization and counterbalancing, conditional branching, as well as those that nest or combine these design elements.
"block_sequence"
can be (1) block names, (2) participant group dictionaries, (3) conditional branch dictionaries, or (4) dedicated keyword instructions.This page is organized by experimental design elements, so that researchers may more easily locate the resources for their particular design of interest. Links will take you to each individual section.
We highly recommend reading the "Example Code" section of each design type, as it contains detailed explanations for how each experimental design can be implemented.
Block Order
Counterbalanced Groups
Conditional Branching
"block_sequence"
in the order you would like them to be presented.{
"type": "blocking",
"blocks": {
// block names are defined by the user and can be anything you want
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
}
},
"block_sequence": ["block_2", "block_1"]
}
This procedure definition presents "block_2"
before "block_1"
for all participants.
"$randomize"
keyword."$randomize"
dictionary will always be truly random, making it possible that some of the randomizations will never be presented to any participants. This can be avoided using the "$factorialize"
keyword (see Randomized Sequence Per Group, Balanced Assignment).{
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
},
"block_3": {
// block_3 definition here
}
},
"block_sequence": [{"$randomize": ["block_1", "block_2", "block_3"]}]
}
During a session of this study, each participant will be presented with a randomized ordering of 3 blocks (e.g., "block_2"
, "block_1"
, "block_3"
).
It is also possible to randomize only part of the complete block sequence per participant:
{
"type": "blocking",
"blocks": {
// block definitions here
},
"block_sequence": ["block_1", {"$randomize": ["block_2", "block_3"]}]
}
During a session of this study, each participant will be presented first with "block_1"
, then the remaining two blocks in random order.
The keys of each dictionary should be user-defined group names (i.e., they are not dedicated keywords, such as
"$randomize"
, and they are not branch names).
{
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
},
"block_3": {
// block_3 definition here
},
"block_4": {
// block_4 definition here
}
},
"block_sequence": [
{
"GroupA": ["block_1", "block_2", "block_4"],
"GroupB": ["block_1", "block_3", "block_4"]
}
]
}
During a session of this study, half of all participants will be assigned to “GroupA”
, who will be presented "block_1"
, "block_2"
, and then "block_4"
. The other half of participants will be assigned to “GroupB”
, who will be presented "block_1"
, "block_3"
, and then "block_4"
.
It is possible to simplify the above definition by putting the common blocks outside the participant group dictionary:
{
"type": "blocking",
"blocks": {
// block definitions here
},
"block_sequence": [
"block_1",
{
"GroupA": ["block_2"],
"GroupB": ["block_3"]
},
"block_4"
]
}
This has the exact same effect as the code provided before, but it highlights the between-subject manipulation. In general, blocks outside participant group dictionaries will be presented to all participants, and each participant group will experience their own sequence of blocks as specified in the dictionaries. Researchers only need to define participant groups for the part of a study that actually differs among groups.
"$randomize"
keyword.{
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
},
"block_3": {
// block_3 definition here
},
"block_4": {
// block_4 definition here
}
},
"block_sequence": [
{
"GroupA": {"$randomize": ["block_1", "block_2", "block_4"]},
"GroupB": {"$randomize": ["block_1", "block_3", "block_4"]}
}
]
}
During a session of this study, half of all participants will be assigned to “GroupA”
, who will be presented "block_1"
, "block_2"
, and "block_4"
in random order. The other half of participants will be assigned to “GroupB”
, who will be presented "block_1"
, "block_3"
, and "block_4"
in random order.
It is possible to apply the "$randomize"
keyword to a group-specific block sequence. For example:
{
"type": "blocking",
"blocks": {
// block definitions here
},
"block_sequence": [
"block_1",
{
"GroupA": ["block_2", "block_3"],
"GroupB": {"$randomize": ["block_2", "block_3"]}
},
"block_4"
]
}
In this case, the between-subject manipulation is whether "block_2"
and "block_3"
are presented in a fixed order ("GroupA"
) or a random order ("GroupB"
). During a session of this study, all participants will be presented with "block_1"
. Participants assigned to “GroupA”
will then be presented with "block_2"
and "block_3"
in that order. Participants in ”GroupB”
will be presented with a randomized ordering of ”block_2”
and ”block_3”
. All participants will be presented with "block_4"
at the end.
$factorialize
keyword.{
"type": "blocking",
"blocks": {
// block definitions here
},
"block_sequence": [
{"$factorialize": {"my_group": ["block_1", "block_2", "block_3"]}}
]
}
This code example creates an exhaustive set of counter-balanced participant groups corresponding to the permutations of a block sequence. That is, FindingFive will automatically create a group for each of the 3! = 6 permutations of the blocks defined after "my_group"
. The groups will be named "my_group1"
, "my_group2"
… "my_group6"
, where the user-defined base group name (in this case "my_group"
) is appended with a number corresponding to which permutation of the block sequence the group received.
The algorithm used to assign the permutations into groups always uses the same ordering to assist in identifying which group received which order. In our example above, "my_group1"
will always get the order ["block_1", "block_2", "block_3"]
; "my_group2"
will always get the order ["block_1", "block_3", "block_2"]
; "my_group3"
will always get the order ["block_2", "block_1", "block_3"]
; and so on.
As with participant grouping and the "$randomize"
keyword, the "$factorialize"
keyword can be applied to a subset of the block sequence:
{
"type": "blocking",
"blocks": {
//block definitions here
},
"block_sequence": [
"block_1",
{"$factorialize": {
"my_group": ["block_2", "block_3"]
}}
]
}
This setup is equivalent to the following, where the participant groups are manually defined:
{
"type": "blocking",
"blocks": {
//block definitions here
},
"block_sequence": ["block_1",
{"my_group1": ["block_2", "block_3"],
"my_group2": ["block_3", "block_2"]}]
}
"blocks"
, then add that branching block and a subsequent branch dictionary to the "block_sequence"
.{
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
},
"branching_block": {
// we show only the branching instructions here for illustration purposes
// one still needs to define all the other components of a block
"branching": {
"method": "accuracy",
"triggers": [{"trial_template": "TRIAL_TEMPLATE_NAME",
"response": "RESPONSE_NAME"}],
"min_score": 0.8,
"branches": {"A": true, "B": false}
}
}
},
"block_sequence": [
"branching_block",
{
"A": ["block_2"],
"B": ["block_1"]
// here "A" and "B" are recognized as branches because they have been defined above already
}
]
}
Given this setup, participants who achieved a minimum accuracy of 80% on trials from the template "TRIAL_TEMPLATE_NAME"
that contain the response "RESPONSE_NAME"
will see "block_2"
, while the rest of the participants will see "block_1"
. The assignment of participants into these branches is conditioned upon their performance in a preceding block.
For other types of branching evaluation methods, see branching block.
Intervening blocks can be inserted between a branching block and its corresponding branch dictionaries. For example, the "block_sequence"
in the above example could be:
{
"block_sequence": ["branching_block", "block_3",
{"A": ["block_2"], "B": ["block_1"]}]
}
In this case, participants are assigned to either Branch A or Branch B at the end of "branching_block"
. However, this assignment has no effect on the presentation of "block_3"
- all participants will see it. The effect of conditional branching takes place only when a branch dictionary is encountered in the "block_sequence"
.
"blocks"
, then add that branching block and a subsequent branch dictionary to the "block_sequence"
. Add an exit block to the "block_sequence"
for the branch that you would like to exit the study early.There are cases where you may want participants who are assigned to one branch to exit the study without seeing further blocks, while participants who are assigned to another branch continue on and complete more blocks. This can be achieved with the built-in exit block. There is no need to define the exit block in your procedure, simply call it in your block sequence by writing "$exit"
:
{
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"branching_block": {
// we show only the branching instructions here for illustration purposes
// one still needs to define all the other components of a block
"branching": {
"method": "accuracy",
"triggers": [{"trial_template":
"TRIAL_TEMPLATE_NAME",
"response": "RESPONSE_NAME"}],
"min_score": 0.8,
"branches": {"A": true, "B": false}
}
},
"block_2": {
// block_2 definition here
},
"block_3": {
// block_3 definition here
},
"debriefing_block": {
// debriefing_block definition here
},
},
{
"block_sequence": ["block_1", "branching_block",
{"A": ["debriefing_block", "$exit"],
"B": ["block_2"]},
"block_3", "debriefing_block"]
}
In this case, all participants see "block_1"
and "branching_block"
. If they are assigned to branch "A"
at the end of the branching block, they then see "debriefing_block"
and exit the study. If they are assigned to branch "B"
, they see "block_2"
and "block_3"
before seeing "debriefing_block"
and then exiting the study. The built-in exit block is especially useful for studies designed with multiple exit points.
"blocks"
. Within the "block_sequence"
, put the branching block outside participant group dictionaries, and the branch dictionaries within the participant group dictionaries.{
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
},
"branching_block": {
// we show only the branching instructions here for illustration purposes
// one still needs to define all the other components of a block
"branching": {
"method": "accuracy",
"triggers": [{"trial_template":
"TRIAL_TEMPLATE_NAME",
"response": "RESPONSE_NAME"}],
"min_score": 0.8,
"branches": {"A": true, "B": false}
}
}
},
"block_sequence": [
"branching_block",
// branch dictionaries are nested within the participant group dictionary
{
"groupA": {"A": ["block_2"], "B": ["block_1"]},
"groupB": {"A": ["block_1"], "B": ["block_2"]}
}
]
}
In this case, FindingFive will automatically assign participants to either "groupA"
or "groupB"
at the beginning of the study (this is how participant grouping works). Both groups will then experience the same "branching_block"
. Participants of both groups will get assigned to either branch "A"
or branch "B"
depending on their responses in the "branching_block"
. Crucially, participants of "groupA"
who are assigned to branch ”A”
will see "block_2"
, whereas participants of "groupB"
who are assigned to branch "A"
will see "block_1"
.
In other words, participants of different groups of participants can be evaluated on the same branching criteria and yet receive different branching outcomes.
"blocks"
. Within "block_sequence"
, put each of the different branching blocks within its own participant group dictionary. {
"type": "blocking",
"blocks": {
"block_1": {
// block_1 definition here
},
"block_2": {
// block_2 definition here
},
"branching_block": {
// we show only the branching instructions here for illustration purposes
// one still needs to define all the other components of a block
"branching": {
"method": "accuracy",
"triggers": [{"trial_template":
"TRIAL_TEMPLATE_NAME",
"response": "RESPONSE_NAME"}],
"min_score": 0.8,
"branches": {"A": true, "B": false}
}
}
"branching_block2": {
// we show only the branching instructions here for illustration purposes
// one still needs to define all the other components of a block
"branching": {
"method": "accuracy",
"triggers": [{"trial_template":
"TRIAL_TEMPLATE_NAME",
"response": "RESPONSE_NAME"}],
"min_score": 0.50001,
"branches": {"A": true, "B": false}
}
}
},
"block_sequence": [
{
"groupA": ["branching_block", {"A": ["block_2"], "B": ["block_1"]}],
"groupB": ["branching_block2", {"A": ["block_1"], "B": ["block_2"]}]
}
]
}
In this case, FindingFive will automatically assign participants to either "groupA"
or "groupB"
at the beginning of the study (this is how participant grouping works). Participants in "groupA"
will thus have a stricter accuracy requirement than those in "groupB"
(80% vs. above chance) due to the different branching blocks used in the two groups. Finally, participants of both groups will be assigned to either branch "A"
or branch "B"
depending on their accuracy in the branching block.
This example shows not only group-specific branching, but it also uses Group-specific Branches. Such a complex experimental design is perhaps not common, but the good news is that FindingFive does support it if your study definitely requires such a setup.