Conditional training phase

PennController for IBEX Forums Support Conditional training phase

Tagged: 

This topic contains 8 replies, has 3 voices, and was last updated by Jeremy Jeremy 2 months, 3 weeks ago.

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author
    Posts
  • #6382
    Avatar
    suz
    Participant

    Dear all,

    I was wondering, following up on this topic, whether (or how) I can make the training phase in a maze task such that training trial only ends when the participant has completed N sentences successfully. Background: the maze task is quite unnatural, so if the training phase only has two or three items, but the participant fails on all of them, that’s hardly a successful training phase; in turn, if a participant is quick on the uptake, having to go through five or six items might be unnecessary.

    So in other words, I was wondering if there was a way to add a conditional loop that counts the numbers of “successes”, and aborts the trial when it equals two, but as long as that condition is not met, it continues to loop through the file “training.csv”, allowing to present, say, four training items continually until success = 2 (I guess once I know how this can be done in principle, I’d be fine to add a condition that aborts the trial after 10 unsuccessful attempts to avoid infinite looping):

    
    Template("training.csv", row =>
        newTrial("training",
    
            newController("Maze", {s: row.Sentence, a: row.Distractor})
                .css("font-size", "1.5em")
                .css("font-family", "Verdana")
                .print()
                .log()
                .wait()
                .remove()
                .test.passed()
                .failure(newText("<br/>oops!").css("font-size", "1.5em").css("color", "red").print())
                .success(newText("<br/>great!").css("font-size", "1.5em").css("color", "green").print())
    
            ,
            newTimer(500).start().wait()
        )
    )
    
    

    From what I understand, I need to know where “success” is stored. Is this task possible in this code or would I need a separate function elsewhere? Is there a topic that addresses this? Afaik, it’s a rather commonly desired property, but I couldn’t find anything in the forum or the doc files (given my inexperience with JS).

    Any help much appreciated, as always.

    Best,
    Susanne

    • This topic was modified 11 months ago by Avatar suz.
    • This topic was modified 11 months ago by Avatar suz.
    #6385
    Jeremy
    Jeremy
    Keymaster

    Hi Susanne,

    You can increment a Var element upon success, check the value of that Var element at the beginning of your trials and only run them if it’s below 2. No need to resort to plain javascript:

    Template("training.csv", row =>
        newTrial("training",
            newVar("training_successes", 0)
                .global()
                .test.is( v => v > 2 )
                .success( end() )
            ,
            newController("Maze", {s: row.Sentence, a: row.Distractor})
                .css("font-size", "1.5em")
                .css("font-family", "Verdana")
                .print()
                .log()
                .wait()
                .remove()
                .test.passed()
                .failure( newText("<br/>oops!").css("font-size", "1.5em").css("color", "red").print() )
                .success(
                    getVar("training_successes").set( v => v+1 ),
                    newText("<br/>great!").css("font-size", "1.5em").css("color", "green").print()
                )
            ,
            newTimer(500).start().wait()
        )
    )

    Let me know if you have questions

    Jeremy

    #6386
    Avatar
    suz
    Participant

    Hi Jeremy,

    This is brilliant, thanks! So I gather that at failure it cannot re-use or re-loop through trainings.csv (judging from this topic I just found here)? That’s fine, I’ll just have 10 or so training items then, that should do the trick. (The progress bar is relative to the full number of possible items, so for early-finishers this will ‘jump’ a little, but that’s not a problem.)

    Again, thanks a lot for your swift response, I’m getting the hang of things!

    Best,
    Susanne

    #6387
    Jeremy
    Jeremy
    Keymaster

    Hi Susanne,

    Sorry, I hadn’t understood your question. You are correct, it’s not possible to re-loop through training.csv using PCIbex at the moment.

    Let me know if you have more questions

    Jeremy

    #6388
    Avatar
    suz
    Participant

    Hi Jeremy,

    Nah, that’s all for now, and exactly what I needed for the intended primary purpose. Thanks!

    —Susanne

    #7129
    Avatar
    ginopino09
    Participant

    Hello Jeremy,
    I’m sorry I don’t if I can continue this thread with a similar issue.

    I’m trying to ascreening test for my experiment where participants will have to score at 70% in an easy English test. If they do not reach this threshold they are not allowed to continue the experiment. I’m having problems even with calculating the test score.

    AddTable("LEX",`WORDS,RES
    PLATERY,F
    DENIAL,J
    GENERIC,J
    MENSIBLE,F
    SCORNFUL,J
    STOUTLY,J
    ABLAZE,J
    JERMSHAW,F')
    
    Template("LEX", row=> 
        newTrial("Engl_prof",
            newVar("score", 0).global(),
                newText(row.WORDS).print("center at 50vw","middle at 50vh"),
            ,
            newText("<span style='color:red'><b>F = it doesn't exist</span></b>, <span style='color:green'><b>J = it exists</span></b>").print("center at 50vw","middle at 75vh"),
            newKey("lext","FJ")
            .wait()
            .log()
            .callback(
                getKey("lext")
                    .test.pressed(row.RES)
                    .success(getVar("score").set(v=>v+1))
                    
            ))
         
    ),
     newTrial("resul",
        newVar("score").global(),
        newText("yscore")
            .before(newText("Your score is: "))
            .text(getVar("score"))
            .after(newText("/60"))
            .print(),
        newButton("Ok").print().wait(),
        newVar("score").global(),
        getVar("score").test.is( v => v > 41 )
            .success(end)
            .failure(newText("I'm sorry but your score is too low. You cannot continue the experiment.").print().wait())
            
            )
    

    I saw that you explained this method somewhere else, but I cannot figure out the problem.

    Best,

    Giorgio

    #7130
    Jeremy
    Jeremy
    Keymaster

    Hi,

    The code you posted has several syntax errors that make it crash. If it comes from an existing project, please consider sharing the demonstration link. Or, if you directly report some code here, try to copy-paste it from the existing project so no new errors are introduced in the process

    This is the code I tested myself, after fixing the syntax errors:

    AddTable("LEX",`WORDS,RES
    PLATERY,F
    DENIAL,J
    GENERIC,J
    MENSIBLE,F
    SCORNFUL,J
    STOUTLY,J
    ABLAZE,J
    JERMSHAW,F`)
    
    Template("LEX", row=> 
        newTrial("Engl_prof",
            newVar("score", 0).global()
            ,
            newText(row.WORDS).print("center at 50vw","middle at 50vh")
            ,
            newText("<span style='color:red'><b>F = it doesn't exist</span>>/b>, <span style='color:green'><b>J = it exists</span></b>")
                .print("center at 50vw","middle at 75vh")
            ,
            newKey("lext","FJ")
                .wait()
                .log()
                .callback(
                    getKey("lext")
                        .test.pressed(row.RES)
                        .success(getVar("score").set(v=>v+1))
                )
        )
    )
    
    newTrial("result",
        newVar("score").global(),
        newText("yscore")
            .before(newText("Your score is: "))
            .text(getVar("score"))
            .after(newText("/60"))
            .print()
        ,
        newButton("Ok").print().wait(),
        newVar("score").global(),
        getVar("score").test.is( v => v > 41 )
            .success(end)
            .failure( newText("I'm sorry but your score is too low. You cannot continue the experiment.").print().wait() )
            
    )

    When I ran the experiment, the debugger immediately reported an error:

    Ambiguous use of getVar(“score”): more than one elements were created with that name-- getVar(“score”) will refer to the first one
    

    Indeed, in the second newTrial you create the “score” Var element twice, so I took the second one out, and then I was able to run the experiment with no warnings or errors

    Your main problem here is that you associate a callback to the Key element after a keypress happened. In fact you don’t need to use callback at all: all you want to do is wait for a keypress, and do something after that (namely, a test) and wait already gives you that:

    newKey("lext","FJ")
        .wait()
        .log()
        .test.pressed(row.RES)
        .success(getVar("score").set(v=>v+1))
    

    Now, your “result” (“resul” in your original code) trial checks whether the value of the “score” Var element is greater than 41, but since your table only defines 8 trials, of course you’ll never pass that threshold, even with a perfect score. 70% of 8 is 5.6, so you could replace 41 with 5. You could also print the “OK” button only if the test is a success, thus only letting the accurate participants continue:

    newTrial("result",
        newVar("score").global(),
        newText("yscore")
            .before(newText("Your score is: "))
            .text(getVar("score"))
            .after(newText("/8"))
            .print()
        ,
        newButton("Ok"),
        getVar("score").test.is( v => v > 5 )
            .success(getButton("OK").print())
            .failure( newText("I'm sorry but your score is too low. You cannot continue the experiment.").print() )
        ,
        getButton("OK").wait()
    )
    

    One caveat: it is against some recruitment platforms’ policies (and maybe some IRB policies?) to prevent a participant who started your experiment from completing it, so this is something you might want to double-check

    Jeremy

    #7133
    Avatar
    ginopino09
    Participant

    Great thank you, it works!
    My actual table has 60 trials, this is why of the number is used.
    Also, thank you for the warning about recruitment policies, we already did that and it’s fine as long as we pay for their time and they are informed from the beginning about the screening test.

    I have another silly question.
    I need block order randomization (no need to counterbalance).
    I see that you suggested in another post to do something like this:

     ( Math.random()>=0.5 ? [
    Sequence("intro","block1","block2","results")
    
    ] : [
    
    Sequence("intro","block2","block1","results")
    
     ])
    

    But what if I have more blocks and I need to randomized them between 4 orders?
    Or even more, like 24 orders?
    Do I use the same math.random function?

    If this questions doens’t belong here, I can delete it and move it below a post with similar requests.

    Thank you again for your help.

    Giorgio

    #7136
    Jeremy
    Jeremy
    Keymaster

    Hi Giorgio,

    If you have many blocks, I recommend the following approach:

    var blocks = ["block1","block2","block3","block4"];
    fisherYates(blocks);
    
    Sequence("intro",...blocks,"results")
    

    Jeremy

Viewing 9 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic.