On this page, we will see how to use PennController‘s functions to generate multiple template-based trials from a spreadsheet.
For this sample trial, you need to use the import method to retrieve the image files we will be using.
Click on Update from git repo and enter the following URL:
https://github.com/PennController/Tutorial.git and replace
spreadsheet in the branch box, then click the Sync button.
You should see a confirmation message appear below the button, reading Success: N files modified. If you don’t see the message, try clicking again. If it still does not work, reload your Ibex page and try again.
Warning: whenever you click on Sync, the content of the file main.js is erased and reverts back to the script in the Basics section below.
Preparation of the table
On the previous page, we ended up defining four trials: 2 picture and 2 rating trials. Both trials in each pair had exactly the same format, with only a few parameters varying from one trial to the other.
Rather than manually copying the same code over and over, editing the variable parts each time (a method which is prone to fatal typos!) we will create a spreadsheet that associates each trial with its variables, and use that spreadsheet to automatically take care of the copying for us by feeding a template.
Rating trials table
For the moment, we will only deal with the rating trials, to get a sense of how PennController handles the spreadsheet-template interface.
Using your favorite spreadsheet editor, create a table for the rating trials like the one below, or download it from here.
|To me the color green is…|
|To me the color purple is…|
Adding a table to the Ibex project
Save your spreadsheet as a CSV file (e.g. input.csv) and upload it to the folder chunk_includes of your Ibex project.
Generating trials with PennController.Template
We will now use the
PennController.Template function to generate Ibex items from the content of the spreadsheet. This is how we use it:
PennController.ResetPrefix(null); PennController.Template( // 'row' will successively point to each row of the table (feel free to use another name) row => PennController( // row.Sentence will iteratively take the value of the column 'Sentence' for each row newText( "sentence" , row.Sentence ) , newScale("judgment", "cold", "cool", "lukewarm", "warm", "hot") .settings.labelsPosition("top") .settings.before( getText("sentence") ) .settings.size("auto") .print() .wait() ) );
As you can see, the template’s structure is identical to the rating items we defined before, but we replaced the content of the Text element with
row.Sentence. This is how it works:
Template goes through each row of the spreadsheet, fills
row (or whatever name you use before
=> PennController() with the values of the cells for the row it is currently inspecting, and generates an item using the template. Since our spreadsheet has two rows, it will use the template twice to generate two items, with
row.Sentence successively taking its value from the Sentence cell of the first and then the second row.
Let us add the picture trials back in. We will create a new spreadsheet with two columns: one for each patch-image of a given trial. Let’s name these two columns Color1 and Color2.
|Which patch is greener?||green1.png||green2.png|
|Which patch is purpler?||purple1.png||purple2.png|
Two templates for two spreadsheets
Save your table as a CSV file and name it picture.csv, then upload it under chunk_includes. We now need to define a new template based on the structure of the picture trials we scripted before, so we will call
Template a second time. But since we are using a different table for the two different types of trial, we need to make sure that each
Template commands picks the right CSV file. Just insert the appropriate filename as the first parameter, like this:
// Show the picture trials first (though we generate them second) PennController.Sequence( randomize("picture") , randomize("rating") ); PennController.ResetPrefix(null); // As before, we use Template to define a template // But now, we also specify the CSV filename PennController.Template( "input.csv" , row => PennController( "rating" , newText( "sentence" , row.Sentence ) , newScale("judgment", "cold", "cool", "lukewarm", "warm", "hot") .settings.labelsPosition("top") .settings.before( getText("sentence") ) .settings.size("auto") .print() .wait() ) ); // We use Template a second time to define a template for the 'picture' trials // This template only uses the table in picture.csv PennController.Template( "picture.csv" , row => PennController( "picture" , defaultImage .settings.size(200, 200) , newText("test sentence", row.Sentence) .print() , newCanvas("patches", 500, 200) .settings.add( 0, 0, newImage("color1", row.Color1) ) .settings.add( 300, 0, newImage("color2", row.Color2) ) .print() , newSelector("patch") .settings.add( getImage("color1") , getImage("color2") ) .wait() ) );
Under the hood, this code generates exactly the same script from the page before: it generates 4 simple PennController trials for us. This way, we can manipulate the order of presentation of the items in the
shuffleSequence variable the same way we did before.
Two conditions per item
Let’s say we want each of our picture trials to come in two versions: one version with the comparative as before, and one version with a less comparative instead. That is, each item now comes in two variants. We have to reflect this in our spreadsheet:
|More||Which patch is greener?||green1.png||green2.png|
|Less||Which patch is less green?||green1.png||green2.png|
|More||Which patch is purpler?||purple1.png||purple2.png|
|Less||Which patch is less purple?||purple1.png||purple2.png|
|More||Which patch is beiger?||beige1.png||beige2.png|
|Less||Which patch is less beige?||beige1.png||beige2.png|
|More||Which patch is oranger?||orange1.png||orange2.png|
|Less||Which patch is less orange?||orange1.png||orange2.png|
We inserted one column, Group, and duplicated each row to reflect our manipulation. The Group column defines different groups of participants: for any given participant, the template will generate trials using either only the More rows, or only the Less rows.
Alternatively, we could choose to show one group of participants half the items in one variant, and half the items in the other variant—the other group of participants would see the complimentary half-half distribution. Let’s label one group A and the other group B. Simply cycle through the items by defining the Group column as shown below: participants from group A will see green and beige with the more comparative and purple and orange with the less comparative, participants from group B will see green and beige with the less comparative and purple and orange with the more comparative.
|A||Which patch is greener?||green1.png||green2.png|
|B||Which patch is less green?||green1.png||green2.png|
|B||Which patch is purpler?||purple1.png||purple2.png|
|A||Which patch is less purple?||purple1.png||purple2.png|
|A||Which patch is beiger?||beige1.png||beige2.png|
|B||Which patch is less beige?||beige1.png||beige2.png|
|B||Which patch is oranger?||orange1.png||orange2.png|
|A||Which patch is less orange?||orange1.png||orange2.png|
Whichever group manipulation you end up going with,
PennController.Template automatically detects the presence of a Group column and generates group-specific trials accordingly, so whichever table you use, you can keep the script from above exactly as it is.
Once you have modified your picture spreadsheet, save it on your device (if you did not download it from the link above) and then in your project on PCIbex Farm click on upload new version to the right of picture.csv and select the new CSV file from your device.
Controlling group assignment
Ibex provides different methods to control which group is running. If you simply click the link of your experiment, Ibex will use its internal counter to choose a group. By default, the counter is increased each time a participant complete the experiment. In your case, since your design defines two different groups, clicking the link will assign you to a different group depending on whether the task has been completed an even or an odd number of times. Feel free to try it yourself, completing and not completing the task at times, to see the effect.
If you want more control over group assignment, you can directly modify the URL of the experiment, by replacing the
experiment.html part at the end with
N is a number used to override the internal counter’s value. In this case, using
server.py?withsquare=0 (even) or
server.py?withsquare=1 (odd) will attribute different groups. This is helpful when you send the URL around for data collection but want to control which group your participants end up in.
Next page: Data Collection & Data Analyses