====== Rotate Pages ======
This chapter describes how to use ''[[:en:create:functions:setpageorder]]'' to present the pages of the questionnaire in a random order. This is often easier than randomly distributing content across pages.
**Important:** You have to give the pages which are included in the rotation a manual [[:en:glossary#page_ids|Page ID]] at **Composing Questionnaire**.
**Important:** The command ''setPageOrder()'' can __not__ be combined with other commands that manipulate the page order: Using the following commands will cause the page order to be canceled: ''setNextPage()'', ''loopPage()'', ''loopToPage()'' and another ''setPageOrder()''.
**Note:** With ''setPageOrder()'' you have always to specify where to continue after the last rotated page in the questionnaire. The examples below demonstrate this -- just don't forget to do it, otherwise (depending on the sequence) pages will be shown twice.
**Note:** The [[:en:results:variables#response times|duration TIME001, TIME002, ...]] stored in the data set always refers to the pages as they were created under **Composing Questionnaire**. The dwell time for page 3 is therefore always stored in TIME003, regardless of whether page 3 is shown at position 3 or (due to a rotation) much later.
===== Rotate Blocks (Basics) =====
In the easiest case, two (or more) sections of the questionnaire should be displayed in random order:
* One group gets first section 1 (block 1) and then section 2 (block 2) presented.
* The other group gets first section 2 (block 2) and then section 1 (block 1) displayed.
In this example, an additional questionnaire page with the identifier "gap" is to be displayed between the two blocks.
{{:de:create:fig.rotation-pages.blocks.png|Rotating page-blocks}}
==== Step 1 ====
Enter [[:en:glossary#page_ids|Page IDs]] for the pages, e.g. "STIM1a", "STIM1b", "gap", etc. in the example. Also give an identifier to the page where it continues after the rotated pages. In the example this is the page "posttest".
==== Step 2 ====
Create a random generator and write in //Codes (Contents)// the possible pageorders. In this example the random generator has the ID "RG01" and the following contents:
STIM1a-STIM1b, gap, STIM2a-STIM2b
STIM2a-STIM2b, gap, STIM1a-STIM1b
As a page sequence, simply specify the page identifiers separated by commas. You can also specify several consecutive pages with a hyphen ''first-last''. This is especially clearer if your blocks contain more than 2 pages.
{{:de:create:scr.rotation-pages.random-generator.png|random generator with page orders}}
==== Step 3 ====
On the page just before the rotation (this page "Pre-Test" has no page identifier in the example), add the following PHP code. This draws a note from the random generator and passes the result to ''setPageOrder()''.
question('RG01'); // Draw note from the random number generator
$pages = value('RG01', 'label'); // Read out drawn page sequence
setPageOrder($pages, 'posttest'); // Apply page sequence
**Note:** Note the second parameter ''%%'posttest'%%'' in the ''setPageOrder()'' function. This determines where to continue after the rotation is processed. In your code you have to change this to your used page ID.
If you want to write the code a little more compact:
question('RG01');
setPageOrder(value('RG01', 'label'), 'posttest');
{{:de:create:scr.rotation-pages.php-code.png|PHP code for page order}}
===== Rotate Singe Pages =====
If there are several pages or blocks whose sequence is to be randomly rotated, then there may be a large number of possible sequences. In the following example the pages "S1" to "S5" should be presented in a random order.
{{:de:create:fig.rotation-pages.single.png|rotate single pages}}
Mathematically, there are ''5! = 120'' possible page sequences.
**Note:** If rotation plays a very important role for your study, for example because you are investigating row order effects, then it may make sense to list all 120 possible page sequences individually and store them in a random generator, as described above. In a spreadsheet like LibreOffice Calc or Excel, this is done by copy & paste quite quickly. __Only in this way__ can you ensure, assuming a sufficient number of respondents, that really all possible page sequences are also tested.
In many cases, however, the aim is only to ensure a little mixing of the sides. To do this, proceed as follows:
- Create a random generator that contains the individual pages as slips of paper.
- In the random number generator, specify that all slips should be drawn in each interview.
- Use PHP code to read the pulled pages and pass them to ''setPageorder()''.
{{:de:create:scr.rotation-pages.random-pages.png|random generator with single pages}}
The random number generator stores the drawn slips in separate variables. In the PHP code, use the function ''[[:en:create:functions:valuelist]]'' to read all variables at once. The random generator has the ID "RG02" in this example.
question('RG02'); //Draw slips in random order
$pages = valueList('RG02', NULL, 'label'); // Drawn slips
setPageOrder($pages, 'posttest'); // Define pages as page sequence
This PHP code is again placed on the page in the questionnaire that comes directly before the rotated pages. So in this example again on the page "Pre-Test".
===== Certain Pages in Fixed Sequence ====
Of course, the above example is not limited to individual pages: In the random generator also blocks of multiple pages can be entered. In the following example the pages "S2" and "S3" should always follow each other. But the position between the other pages should be random.
{{:de:create:fig.rotation-pages.chained.png|}}
Therefore, do not enter these two pages separately in the random generator, but as a block. Here again in the "from-to" notation.
S1
S2-S3
S4
S5
Since there are now only 4 slips, continue to enter in the random number generator that 4 slips are drawn per interview. The PHP code is identical to the previous example [[#rotate_singe_pages|Rotate single pages]].
===== Single Pages at Fixed Position ====
The pages in the questionnaire should be rotated randomly, but a single page should always appear at a certain position? In the following example, five pages "S1", "S2", "gap", "S3" and "S4" are to be rotated again, but the page "gap" is always to be displayed as the third page.
{{:de:create:fig.rotation-pages.gap.png|}}
**Tip:** If there are actually only 4+1 pages, there are only 24 possible page sequences. So you could also follow the instructions above: [[#rotate_blocks_basics|Rotate Blocks]].
Effectively, only 4 pages are rotated here and this is also entered in the random generator. In this example the random generator has the identifier RG04.
S1
S2
S3
S4
The page "gap", which should remain at a fixed position, is not entered in the random generator. And since there are only 4 slips in the random generator, it is again entered that 4 slips have to be drawn per interview.
In the PHP code all variables of the random generator are read out again by means of ''valueList()'', thus a random sequence of The function returns an [[:en:create:array|array]], which might look like this.
|S3|S1|S4|S2|
Note that the elements in an array are always counted from 0. The first elemet has the index 0, the second has the index 1 etc. This is important right away when we specify where we want the page to "gap".
Now it is necessary to insert the page "gap" on the third position (index 2). One possibility is to use the PHP function [[https://www.php.net/manual/en/function.array-splice.php|array_splice()]].
question('RG04'); // Draw from the random generator
$pages = valueList('RG04', NULL, 'label'); // Liste der Seiten auslesen
array_splice($pages, 2, 0, ['gap']); // Insert page "gap" at index 2
setPageOrder($pages, 'posttest'); // Apply page order
The individual parameters in ''array_splice()'' are:
- The array to be processed,
- the position where to cut (remember: position 3 has index 2)
- the number of element which should possible be deleted (in this case 0, because we do not want to delete something)
- the elements to be added -- "gap" is written in steht hier in square brackets to make it to an array with only one element. But strictly speaking, the function ''array_splice()'' would accept the string (text, that is, the page identifier) even without square brackets.
After the adaptation via ''array_splice()'' the array has the following content:
|S3|S1|gap|S4|S2|
If only one page or block is to be inserted into the array, ''array_splice()'' is very handy. If elements are to be inserted in several places, then it is easier to use ''[[https://www.php.net/manual/en/function.array-slice.php|array_slice()]]'' to cut out the required pieces from the original array and build a new array from them. The function ''[[https://www.php.net/manual/en/function.array-merge.php|array_merge()]]'' merges multiple array fragments into a new array.
question('RG04'); // Draw slips in random order
$pages = valueList('RG04', NULL, 'label'); // Read out the list of pages
$pageOrder = array_merge(
array_slice($pages, 0, 2),
['gap'],
array_slice($pages, 2)
);
setPageOrder($pages, 'posttest'); // Use page order
The call ''array_slice($pages, 0, 2)'' takes 2 pages from index 0 (position 1). The call ''array_slice($pages, 2)'' takes all pages from position 3 (index 2) to the end of the array.
When using ''array_merge()'', the page to be inserted must be enclosed in square brackets. Otherwise this parameter would not be an array.
By the way, ''setPageOrder()'' also allows to specify the blocks as parameters. The function ''array_merge()'' is therefore not mandatory:
question('RG04'); // Draw slips in random order
$pages = valueList('RG04', NULL, 'label'); // Read out the list of pages
setPageOrder(
array_slice($pages, 0, 2),
'gap',
array_slice($pages, 2),
'posttest'
);
===== Rotate Pages Within Blocks =====
This exaple shows how pages can be rotated within blocks. Here the pages "S1" and "S2" should stay together in a random order S1, S2 or S2, S1 and the pages "S3", "S4" and "S5" should also stay together but be rotated among each other.
{{:de:create:fig.rotation-pages.within.png|Rotate blocks of pages}}
==== Fixed Block Sequence (Variant 1) ====
In the first case should the block S1/S2 always be presented first and then the block S3/S4/S5.
**Note:** Only 12 page sequences are possible here. Therefore it can be useful to define the page orders individually. So you could also follow the instructions above: [[#rotate_single_pages|Rotate Single Pages]]
This first variant is connected to the solutions with the random generator above. But since 2 blocks are to be rotated within themselves, two random generators are used. The contents are as follows:
In the first random generator (in the example "RG06") the first two pages are deposited and 2 slips are drawn per interview:
S1
S2
In the second random generator (in the example "RG07") the other pages are deposited and 3 slips are drawn per interview:
S3
S4
S5
In the PHP code, the slips are again drawn in random order, using ''valueList()'' to read the two lists, and then passed directly to ''setPageOrder()''. It also would be possible to merge the two arrays with ''array_merge()'' first but it is not necessary.
question('RG06');
question('RG07');
$pages1 = valueList('RG06', NULL, 'label');
$pages2 = valueList('RG07', NULL, 'label');
setPageOrder($pages1, $pages2, 'posttest');
Again, a shorter notation is possible without the auxiliary variables ''$pages1'' and ''$pages2'':
question('RG06');
question('RG07');
setPageOrder(
valueList('RG06', NULL, 'label'),
valueList('RG07', NULL, 'label'),
'posttest'
);
==== Fixed Block Sequence (Variant 2) ====
In the previous examples, the sequence of pages was stored in the random generator and was thus available in the data set. In many cases, however, the sequence of pages does not even need to be available for the evaluation. In these cases you can work with arrays and the PHP function ''[[https://www.php.net/manual/en/function.shuffle|shuffle()]]''.
In this case you would __not__ use a random generator but place the following PHP code on the page "Pre-Test".
$pages1 = ['S1', 'S2'];
$pages2 = ['S3', 'S4', 'S5'];
shuffle($pages1);
shuffle($pages2);
setPageOrder($pages1, $pages2, 'posttest');
==== Rotated Block Sequence (Variant 1) ====
If the sequence of blocks is to be rotated, then this additional factor can be mapped by another random generator.
**Important:** It might be an idea to simply use ''setPageOrder()'' multiple times for this use case. But this does __not__ work, because if you call ''setPageOrder()'' again, a currently active page order is terminated and the new one is used instead.
The following example assumes that there are 3 blocks whose pages are to be mixed in each case and whose order is also to vary:
* Block 1: S1, S2
* Block 2: S3, S4, S5
* Block 3: S6, S7, S8
If you want to implement this using a random generator (an alternative variant using ''shuffle()'' is described below), you need 4 random generators:
* Random generator 1 (RG01) for the order of the blocks -> Content: block A, block B, block C.
* Random generator 2 (RG02) for block 1 -> Content: S1, S2
* Random generator 3 (RG03) for block 2 -> Content: S3, S4, S5
* Random generator 4 (RG04) for block 3 -> Content: S6, S7, S8
**Important:** In the random generators, as many codes (slips of paper) must be drawn in each case as elements are to be used in the questionnaire. So if three blocks are to be rotated, then "RG01" three slips must be defined and three slips must also be drawn per interview. This is set directly in the random generator.
The 4 random generators get placed on the page __before__ S1. Below the following PHP code is used:
$blockorder = array_values(valueList('RG01'));
$blocks = [
1 => valueList('RG02', null, 'label'),
2 => valueList('RG03', null, 'label'),
3 => valueList('RG04', null, 'label')
];
$overall list = array_merge(
$blocks[$blockorder[0]],
$blocks[$blockorder[1]],
$blocks[$blockorder[2]]
);
setPageOrder($fulllist, 'SD');
By the way, with this solution it is quite simple to place fixed pages between the blocks. So, if the page "F1" is to be shown before block 1, the page "F2" before block 2, and the page "F3" before block 3, one would add the following to the definition of the viarable ''$overall list''.
$overall list = array_merge(
['F1'],
$blocks[$blockorder[0]],
['F2'],
$blocks[$blockorder[1]],
['F3'],
$blocks[$blockorder[2]]
);
==== Rotated Block Sequence (Variant 2) ====
If you do not want to save the presentation sequence, the rotation can also be realized without random generators. For the rotation we use then ''shuffle()''.
The following PHP code first merges the individual blocks into itself and then again an array containing the two blocks. The two blocks are defined here immediately as arrays in an array.
$pages = [
['S1', 'S2'],
['S3', 'S4', 'S5'],
['S6', 'S7', 'S8']
];
// Mix each block in itself
for ($i=0; $i