Sample trial: Rating scale & Input box

NOTE: this page assumes you are familiar with notions covered in this page.

Next: Priming Design.

Setup

Create a new experiment on Ibex. Click on Update from git repo and enter the following URL: https://github.com/PennController/Tutorial.git, then enter rating-input (all lower case, simple dash) in the branch/revision box and click on the Sync button. You should see a confirmation message appear below the button, reading Success: N file 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 file example_data gets erased and reverts back to the code in the Basics section below.

Basics

Let’s say we want to test some predictions about how people associate colors with sensations of warmth. We can ask them to report their judgment on a scale for a given color, e.g. green:

PennController.ResetPrefix(null);

PennController(
    newText("green", "How warm is the color green to you?")
        .print()
    ,
    newScale("judgment", 5) // 5-point scale
        .print()
        .wait()             // Validate upon choice
);

Adding content to the left/right

This is functional, but it would be better if the participant had an idea of how the scale is oriented. Let’s add some text to the left and to the right of the scale:

PennController.ResetPrefix(null);

PennController(
    newText("green", "To me the color green is...")
        .print()
    ,
    newScale("judgment", 5)
        .settings.before( newText("cold", "very cold") )    // Add a text element to the left
        .settings.after(  newText("hot", "very hot")   )    // Add a text element to the right
        .print()
        .wait()
);

Slider

Maybe more continuous measures are more fitted to our model. Presenting the scale as a slider, we can naturally present a 100-point scale:

PennController.ResetPrefix(null);

PennController(
    newText("green", "To me the color green is...")
        .print()
    ,
    newScale("judgment", 100)
        .settings.slider()              // Slider scale
        .settings.size( 200 , "auto" )  // 200px wide
        .settings.before( newText("cold", "very cold") )
        .settings.after(  newText("hot", "very hot")   )
        .print()
        .wait()
    ,
    // Adding a validation button (feels wrong to end the trial when the slider gets released)
    newButton("validate", "Validate")
        .print()
        .wait()
);

Labels

Or maybe we like the 5-point scale, but want to add a label above each button:

PennController.ResetPrefix(null);

PennController(
    // Don't print it yet, we'll now add it to the left of the scale
    newText("green", "To me the color green is...")
        //.print()
    ,
    // Give as many labels as there are buttons
    newScale("judgment",    "cold", "cool", "lukewarm", "warm", "hot")
        .settings.labelsPosition("top")  // Position the labels
        .settings.before( getText("green") )
        .print()
        .wait()
    ,
    newButton("validate", "Validate")
        .print()
        .wait()
);

Alternative response

Maybe some people feel the cold-hot scale is too restricted and want to give a custom response. We can provide them with a text input box as the last option:

PennController.ResetPrefix(null);

PennController(
        newText("green", "To me the color green is...")
        ,
        newTextInput("other", "")   // Don't print it yet
            .settings.before( newText("label input", "other:") )
        ,
        // The last option has no label: it's the 'other' text input
        newScale("judgment",    "cold", "cool", "lukewarm", "warm", "hot", "")
            .settings.labelsPosition("top")
            .settings.before( getText("green") )
            .settings.after( getTextInput("other") )    // Text input box to the right
            .print()
            .wait()
        ,
        newButton("validate", "Validate")
            .print()
            .wait()
);

Dynamic unfolding

Maybe we want to show the other input box only if the participant clicks that option. We will need to use a Test command on the Scale element to check which option was selected.

PennController.ResetPrefix(null);

PennController(
    newText("green", "To me the color green is...")    // Don't print yet
    ,
    newTextInput("other", "")                          // Don't print yet
        .settings.hidden()                             // Make sure it's masked
    ,
    newText("label input", "other")                    // Don't print yet
        .settings.after( getTextInput("other") )       // Input box to the right (hidden for now)
    ,
    // We don't need to create the text input box yet
    newScale("judgment",    "cold", "cool", "lukewarm", "warm", "hot", "")
        .settings.labelsPosition("top")
        .settings.before( getText("green")       )
        .settings.after(  getText("label input") )    // We still need some text saying 'other'
        .print()
        .wait()
    ,
    getScale("judgment")
        .test.selected(5) // The last option has no value: we refer to it by its index (6-1=5)
        .success(
            // If the 5-th option was selected...
            getTextInput("other")
                .settings.visible() // ... reveal the input box
        )
        .failure(
            // Any other option selected: do nothing
        )
    ,
    newButton("validate", "Validate")
        .print()
        .wait()
);

Exercises

  • Reduce the width of the text input box
  • Start with the input box disabled (.settings.disable()) rather than hidden, and enable it upon choice of last option

Questions

The input box does not appear if I click on other after I first clicked on another option. Why? And how can I fix this?

The Test command in the script above is only evaluated after the very first selection on the scale. If the very first click is on the last option, the test is a success and the box appears. If the very first click is on another option, the test fails and the box does not appear. Subsequent choices have no consequence, since the Test command has long been evaluated by then.

What you are trying to do is to set the scale such that, whenever an option is selected, it should check whether it was the last one, and show/hide the input box accordingly. This sounds more like a setting: you are not trying to script the execution of a unique action in a linear series of events. What you are looking for is the Settings command callback.

PennController.ResetPrefix(null);

PennController(
    newText("green", "To me the color green is...")
    ,
    newTextInput("other", "")
        .settings.hidden()
    ,
    newText("label input", "other")
        .settings.after( getTextInput("other") )
    ,
    newScale("judgment",    "cold", "cool", "lukewarm", "warm", "hot", "")
        .settings.labelsPosition("top")
        .settings.before( getText("green")       )
        .settings.after(  getText("label input") )
        .settings.callback( // Whenever an option is selected, do this:
            getScale("judgment")
                .test.selected(5)
                // ... reveal the input box
                .success( getTextInput("other").settings.visible() )
                // ... hide the input box
                .failure( getTextInput("other").settings.hidden()  )
        )
        .print()
        .wait()
    ,
    newButton("validate", "Validate")
        .print()
        .wait()
);

Next page: Priming Design