====== Seiten rotieren ====== Dieses Kapitel beschreibt, wie man mithilfe von ''[[:de:create:functions:setpageorder]]'' die Seiten des Fragebogens in einer zufälligen Abfolge präsentiert. Dies ist oftmals einfacher als die Inhalte zufällig auf die einzelnen Seiten zu verteilen. **Wichtig:** Sie müssen den Seiten im Fragebogen, die an der Rotation beteiligt sind, beim **Fragebogen zusammenstellen** manuell [[:de:glossary#seitenkennung|Seiten-Kennungen]] zuweisen. **Wichtig:** Der Befehl ''setPageOrder()'' kann __nicht__ mit anderen Befehlen Kombiniert werden, welche die Seitenabfolge manipulieren: Die Verwendung der folgenden Befehle führt jeweils dazu, dass die Seitenabfolge abgebrochen wird: ''setNextPage()'', ''loopPage()'', ''loopToPage()'' und ein anderes ''setPageOrder()''. **Hinweis:** Bei ''setPageOrder()'' müssen Sie immer angeben, wo es nach der letzten rotierten Seite im Fragebogen weitergehen soll. In den Beispielen unten wird das demonstriert -- man darf es nur nicht vergessen, sonst werden (je nach Abfolge) Seiten doppelt angezeigt. **Hinweis:** Die im Datensatz gespeicherte [[:de:results:variables#antwortzeiten|Verweildauer TIME001, TIME002, ...]] bezieht sich immer auf die Seiten, so wie sie unter **Fragebogen zusammenstellen** angelegt wurden. Die Verweildauer für Seite 3 wird also immer in TIME003 gespeichert, unabhängig davon, ob Seite 3 an Position 3 gezeigt wird oder (wegen einer Rotation) erst viel später. ===== Blöcke rotieren (Grundlagen) ===== Im einfachsten Fall sollen zwei (oder mehr) Abschnitte des Fragebogens in zufälliger Abfolge angezeigt werden: * Die eine Gruppe bekommt erst Abschnitt 1 (Block 1) präsentiert, dann Abschnitt 2 (Block 2). * Die andere Gruppe bekommt erst Abschnitt 2 (Block 2) vorgelegt, dann Abschnitt 1 (Block 1). In diesem Beispiel soll zwischen den beiden Blöcken noch eine zusätzliche Fragebogen-Seite mit der Kennung "gap" angezeigt werden. {{:de:create:fig.rotation-pages.blocks.png|Rotation von Seiten-Blöcken}} ==== Schritt 1 ==== Tragen Sie bei den Seiten [[:de:glossary#seitenkennung|Seiten-Kennungen]] ein, im Beispiel z.B. "STIM1a", "STIM1b", "gap", u.s.w. Geben Sie auch jener Seite eine Kennung, wo es nach den rotierten Seiten weitergeht. Im Beispiel ist das die Seite "posttest". ==== Schritt 2 ==== Erstellen Sie einen Zufallsgenerator, in welchem Sie die möglichen Seitenabfolgen hinterlegen. In diesem Beispiel hat der Zufallsgenerator die Kennung "RG01" und folgenden Inhalt: STIM1a-STIM1b, gap, STIM2a-STIM2b STIM2a-STIM2b, gap, STIM1a-STIM1b Als Seitenabfolge geben Sie einfach die Seiten-Kennungen durch Kommata getrennt an. Mehrere aufeinander folgende Seiten können Sie auch mit einem Bindestrich ''erste-letzte'' angeben. Das ist vor allem dann übersichtlicher, wenn Ihre Blöcke mehr als 2 Seiten enthalten. {{:de:create:scr.rotation-pages.random-generator.png|Zufallsgenerator mit Seitenabfolgen}} ==== Schritt 3 ==== Fügen Sie auf der Seite direkt vor der Rotation (diese Seite "Pre-Test" hat im Beispiel keine Seitenkennung) den folgenden PHP-Code ein. Dieser zieht einen Zettel aus dem Zufallsgenerator und übergibt das Ergebnis an ''setPageOrder()''. question('RG01'); // Zettel aus dem Zufallsgenerator ziehen $pages = value('RG01', 'label'); // Gezogene Seitenabfolge auslesen setPageOrder($pages, 'posttest'); // Seitenabfolge anwenden **Hinweis:** Beachten Sie den zweiten Parameter ''%%'posttest'%%'' im Befehl ''setPageOrder()''. Damit wird festgelegt, wo es nach dem Abarbeiten der Rotation weitergeht. Falls Sie den Code noch ein wenig kompakter schreiben möchten: question('RG01'); setPageOrder(value('RG01', 'label'), 'posttest'); {{:de:create:scr.rotation-pages.php-code.png|PHP-Code für die Seitenabfolge}} ===== Einzelne Seiten rotieren ===== Wenn es mehrere Seiten oder Blöcke gibt, deren Reihenfolge zufällig rotiert werden soll, dann gibt es unter Umständen eine große Anzahl möglicher Abfolgen. Im folgenden Beispiel sollen die Seiten "S1" bis "S5" in zufälliger Abfolge angezeigt werden. {{:de:create:fig.rotation-pages.single.png|Einzelne Seiten rotieren}} Rechnerisch gibt es ''5! = 120'' mögliche Seitenabfolgen. **Hinweis:** Wenn die Rotation für Ihre Studie eine sehr wichtige Rolle spielt, etwa weil Sie Reihenstellungseffekte untersuchen, dann kann es durchaus sinnvoll sein, alle 120 möglichen Seitenabfolgen einzeln aufzulisten und in einem Zufallsgenerator zu hinterlegen, wie oben beschrieben. In einer Tabellenkalkulation wie LibreOffice Calc oder Excel ist das mittels Copy&Paste recht schnell erledigt. __Nur so__ können Sie sicherstellen, eine ausreichende Anzahl von Befragten vorausgesetzt, dass wirklich alle möglichen Seitenabfolgen auch getestet werden. In vielen Fällen soll aber nur für ein wenig Durchmischung der Seiten gesorgt werden. Dafür gehen Sie wie folgt vor: - Erstellen Sie einen Zufallsgenerator, der die einzelnen Seiten als Zettel beinhaltet. - Legen Sie im Zufallsgenerator fest, dass in jedem Interview alle Zettel gezogen werden sollen. - Verwenden Sie PHP-Code, um die gezogenen Seiten auszulesen und an ''setPageorder()'' zu übergeben. {{:de:create:scr.rotation-pages.random-pages.png|Zufallsgenerator mit einzelnen Seiten}} Der Zufallsgenerator speichert die gezogenen Zettel in separate Variablen. Im PHP-Code verwenden Sie die Funktion ''[[:de:create:functions:valuelist]]'', um alle Variablen auf einmal auszulesen. Der Zufallsgenerator hat in diesem Beispiel die Kennung "RG02". question('RG02'); // Zettel in zufälliger Reihenfolge ziehen $pages = valueList('RG02', NULL, 'label'); // Gezogene Zettel auslesen setPageOrder($pages, 'posttest'); // Seiten als Seitenabfolge definieren Dieser PHP-Code wird wieder auf der Seite im Fragebogen platziert, die direkt vor den rotierten Seiten kommt. Also in diesem Beispiel wieder auf der Seite "Pre-Test". ===== Bestimmte Seiten in fester Abfolge ==== Das obige Beispiel ist natürlich nicht auf einzelne Seiten beschränkt: Im Zufallsgenerator können auch Blöcke mehrerer Seiten eingetragen werden. Im folgenden Beispiel sollten die Seiten "S2" und "S3" immer aufeinander folgen, das aber an zufälliger Position zwischen den anderen Seiten. {{:de:create:fig.rotation-pages.chained.png|}} Tragen Sie diese beiden Seiten dafür nicht separat im Zufallsgenerator ein, sondern als Block. Hier wieder in der "von-bis" Notation. S1 S2-S3 S4 S5 Da es jetzt nur noch 4 Zettel gibt, tragen Sie im Zufallsgenerator weiterhin ein, dass pro Interview 4 Zettel gezogen werden. Der PHP-Code ist identisch mit dem vorigen Beispiel [[#einzelne_seiten_rotieren|Einzelne Seiten rotieren]]. ===== Einzelne Seiten an fester Position ==== Die Seiten im Fragebogen sollen zufällig rotiert werden, aber eine einzelne Seite soll immer an einer bestimmten Position erscheinen? Im folgenden Beispiel gilt es wieder fünf Seiten "S1", "S2", "gap", "S3" und "S4" zu rotieren, aber die Seite "gap" soll immer als dritte Seite angezeigt werden. {{:de:create:fig.rotation-pages.gap.png|}} **Tipp:** Wenn es wirklich nur 4+1 Seiten sind, gibt es lediglich 24 mögliche Seitenabfolgen. Sie könnten also auch der obigen Anleitung [[#bloecke_rotieren_grundlagen|Blöcke rotieren]] folgen. Effektiv werden hier nur 4 Seiten rotiert und dies wird auch so im Zufallsgenerator eingetragen. In diesem Beispiel hat der Zufallsgenerator die Kennung RG04. S1 S2 S3 S4 Die Seite "gap", die an einer festen Position verbleiben soll, wird nicht im Zufallsgenerator eingetragen. Und da es nur 4 Zettel im Zufallsgenerator sind, wird wieder eingetragen, dass pro Interview 4 Zettel zu ziehen sind. Im PHP-Code werden mittels ''valueList()'' wieder alle Variablen des Zufallsgenerators ausgelesen, also eine zufällig Abfolge der 4 Zettel. Die Funktion liefert ein [[:de:create:array|Array]], welches zum Beispiel so aussehen könnte. |S3|S1|S4|S2| Beachten Sie, dass die Elemente in einem Array immer ab 0 gezählt werden. Das erste Element hat also den Index 0, das zweite den Index 1 u.s.w. Das ist gleich wichtig, wenn wir angeben, wo wir die Seite "gap" haben möchten. Nun gilt es also, auf der dritten Position (Index 2) noch die Seite "gap" einzuschieben. Eine Möglichkeit besteht in der Verwendung der PHP-Funktion [[https://www.php.net/manual/de/function.array-splice.php|array_splice()]]. question('RG04'); // Zettel aus dem Zufallsgenerator ziehen $pages = valueList('RG04', null, 'label'); // Liste der Seiten auslesen array_splice($pages, 2, 0, ['gap']); // Seite "gap" an Index 2 einfügen setPageOrder($pages, 'posttest'); // Seitenabfolge anwenden Die einzelnen Parameter in ''array_splice()'' sind: - Das Array, welches bearbeitet werden soll, - die Stelle wo geschnitten werden soll (zur Erinnerung: Position 3 hat den Index 2) - die Anzahl der Elemente, die evtl. entfernt werden sollen (hier also 0, denn wir möchten nichts entfernen) - die Elemente, die eingefügt werden sollen -- das "gap" steht hier in eckigen Klammern, um es in ein Array mit nur einem Element zu verwandeln. Aber streng genommen würde die Funktion ''array_splice()'' den String (Text, also die Seitenkennung) auch ohne eckige Klammern akzeptieren. Nach der Anpassung durch ''array_splice()'' hat das Array also den folgenden Inhalt: |S3|S1|gap|S4|S2| Wenn nur eine Seite oder ein Block in das Array eingesetzt werden soll, ist ''array_splice()'' sehr praktisch. Wenn an mehreren Stellen Elemente eingesetzt werden sollen, dann ist es einfacher, mittels ''[[https://www.php.net/manual/de/function.array-slice.php|array_slice()]]'' die benötigten Stückchen aus dem ursprünglichen Array auszuschneiden und daraus ein neues Array zu bauen. Die Funktion ''[[https://www.php.net/manual/de/function.array-merge.php|array_merge()]]'' fügt mehrere Array-Fragmente zu einem neuen Array zusammen. question('RG04'); // Zettel aus dem Zufallsgenerator ziehen $pages = valueList('RG04', NULL, 'label'); // Liste der Seiten auslesen $pageOrder = array_merge( array_slice($pages, 0, 2), ['gap'], array_slice($pages, 2) ); setPageOrder($pages, 'posttest'); // Seitenabfolge anwenden Der Aufruf ''array_slice($pages, 0, 2)'' entnimmt 2 Seiten ab Index 0 (Position 1). Der Aufruf ''array_slice($pages, 2)'' entnimmt alle Seiten ab Position 3 (Index 2) bis zum Ende des Arrays. Bei Verwendung von ''array_merge()'' muss die Seite, die eingefügt werden soll, zwingend in eckigen Klammern stehen. Sonst wäre dieser Parameter kein Array. Übrigens erlaubt es ''setPageOrder()'' auch, die Blöcke als Parameter anzugeben. Die Funktion ''array_merge()'' ist deshalb nicht zwingend erforderlich. question('RG04'); // Zettel aus dem Zufallsgenerator ziehen $pages = valueList('RG04', NULL, 'label'); // Liste der Seiten auslesen setPageOrder( array_slice($pages, 0, 2), 'gap', array_slice($pages, 2), 'posttest' ); ===== Seiten innerhalb der Blöcke rotieren ===== Dieses Beispiel zeigt, wie man Seiten innerhalb von Blöcken rotieren kann. Hier sollten die Seiten "S1" und "S2" immer beisammen bleiben, aber zufällige in der Abfolge S1,S2 oder S2,S1. Und die Seiten "S3", "S4" und "S5" sollen ebenfalls zusammen bleiben, aber untereinander gemischt werden. {{:de:create:fig.rotation-pages.within.png|Blöcke von Seiten rotieren}} ==== Feste Block-Abfolge (Variante 1) ==== Im ersten Fall soll immer zuerst der Block S1/S2 kommen und anschließend der Block S3/S4/S5. **Hinweis:** Hier sind lediglich 12 Seitenabfolgen möglich. Es kann durchaus sinnvoll sein, diese Seitenabfolgen einzeln zu definieren und vorzugehen, wie oben in der Anleitung [[#einzelne_seiten_rotieren|Einzelne Seiten rotieren]] erklärt. Die erste Variante knüpft an die obigen Lösungen mit Zufallsgenerator an. Da aber 2 Blöcke in sich rotiert werden sollen, werden zwei Zufallsgeneratoren verwendet. Die Inhalte sind wie folgt. Im ersten Zufallsgenerator (im Beispiel "RG06") werden die ersten beiden Seiten hinterlegt und pro Interview 2 Zettel gezogen: S1 S2 Im zweiten Zufallsgenerator (im Beispiel "RG07") werden die restlichen Seiten hinterlegt und pro Interview 3 Zettel gezogen: S3 S4 S5 Im PHP-Code werden die Zettel wieder in zufälliger Reihenfolge gezogen, mittels ''valueList()'' die beiden Listen ausgelesen und dann direkt an ''setPageOrder()'' übergeben. Man könnte die beiden Arrays auch zunächst mittels ''array_merge()'' zusammenfügen, aber das ist nicht notwendig. question('RG06'); question('RG07'); $pages1 = valueList('RG06'); $pages2 = valueList('RG07'); setPageOrder($pages1, $pages2, 'posttest'); Auch hier ist wieder eine kürzere Schreibweise ohne die Hilfsvariablen ''$pages1'' und ''$pages2'' möglich. question('RG06'); question('RG07'); setPageOrder( valueList('RG06'), valueList('RG07'), 'posttest' ); ==== Feste Block-Abfolge (Variante 2) ==== In den vorherigen Beispielen wurde die Abfolge der Seiten im Zufallsgenerator gespeichert und war damit im Datensatz verfügbar. In vielen Fällen muss die Abfolge der Seiten aber für die Auswertung gar nicht vorliegen. In diesen Fällen kann man mit Arrays und der PHP-Funktion ''[[https://www.php.net/manual/de/function.shuffle|shuffle()]]'' arbeiten. In diesem Fall würde man __keinen__ Zufallsgenerator anlegen, sondern nur folgenden PHP-Code auf der Seite "Pre-Test" platzieren. $pages1 = ['S1', 'S2']; $pages2 = ['S3', 'S4', 'S5']; shuffle($pages1); shuffle($pages2); setPageOrder($pages1, $pages2, 'posttest'); ==== Rotierte Block-Abfolge (Variante 1) ==== Wenn die Abfolge der Blöcke rotiert werden soll, dann lässt sich dieser zusätzliche Faktor durch einen weiteren Zufallsgenerator abbilden. **Wichtig:** Man könnte auf die Idee kommen, ''setPageOrder()'' für diesen Anwendungsfall einfach mehrfach zu verwenden. Das funktioniert aber __nicht__, denn wenn man ''setPageOrder()'' erneut aufruft, wird eine gerade aktive Seitenabfolge beendet und stattdessen die neue verwendet. Das folgende Beispiel geht davon aus, dass es 3 Blöcke gibt, deren Seiten jeweils gemischt werden sollen und deren Reihenfolge ebenfalls variieren soll: * Block 1: S1, S2 * Block 2: S3, S4, S5 * Block 3: S6, S7, S8 Möchte man das mittels Zufallsgenerator umsetzen (eine alternative Variante mittels ''shuffle()'' wird unten beschrieben), benötigt man 4 Zufallsgeneratoren: * Zufallsgenerator 1 (RG01) für die Abfolge der Blöcke -> Inhalt: Block A, Block B, Block C. * Zufallsgenerator 2 (RG02) für Block 1 -> Inhalt: S1, S2 * Zufallsgenerator 3 (RG03) für Block 2 -> Inhalt: S3, S4, S5 * Zufallsgenerator 4 (RG04) für Block 3 -> Inhalt: S6, S7, S8 **Wichtig:** In den Zufallsgeneratoren müssen jeweils so viele Codes (Zettel) gezogen werden, wie Elemente im Fragebogen genutzt werden sollen. Wenn also drei Blöcke rotiert werden sollen, dann müssen "RG01" drei Zettel definiert und pro Interview auch drei Zettel gezogen werden. Dies wird direkt im Zufallsgenerator eingestellt. Die 4 Zufallsgeneratoren werden nun auf der Seite __vor__ S1 platziert. Darunter wird folgender PHP-Code verwendet: $blockfolge = array_values(valueList('RG01')); $blocks = [ 1 => valueList('RG02', null, 'label'), 2 => valueList('RG03', null, 'label'), 3 => valueList('RG04', null, 'label') ]; $gesamtliste = array_merge( $blocks[$blockfolge[0]], $blocks[$blockfolge[1]], $blocks[$blockfolge[2]] ); setPageOrder($gesamtliste, 'SD'); Bei dieser Lösung ist es übrigens recht einfach, zwischen den Blöcken noch fixe Seiten zu platzieren. Wenn also vor Block 1 die Seite "F1", vor Block 2 die Seite "F2" und vor Block 3 die Seite "F3" gezeigten werden soll, würde man die Definition der Viarable ''$gesamtliste'' wie folgt ergänzen. $gesamtliste = array_merge( ['F1'], $blocks[$blockfolge[0]], ['F2'], $blocks[$blockfolge[1]], ['F3'], $blocks[$blockfolge[2]] ); ==== Rotierte Block-Abfolge (Variante 2) ==== Falls man die Präsentationsabfolge nicht speichern möchte, lässt sich die Rotation auch ohne Zufallsgeneratoren realisieren. Für die Rotation kommt dann ''shuffle()'' zum Einsatz. Der folgende PHP-Code mischt erst die einzelnen Blöcke in sich und dann noch einmal ein Array, welches die beiden Blöcke beinhaltet. Die beiden Blöcke werden hier gleich als Arrays in einem Array definiert. $pages = [ ['S1', 'S2'], ['S3', 'S4', 'S5'], ['S6', 'S7', 'S8'] ]; // Jeden Block in sich mischen for ($i=0; $i