html layout/event times/selector vs. scale/ compatibility

PennController for IBEX Forums Support html layout/event times/selector vs. scale/ compatibility

Viewing 15 posts - 31 through 45 (of 48 total)
  • Author
    Posts
  • #7625
    Jeremy
    Keymaster

    Hi,

    1. You can either use , in place of ,, or surround your text column which contains ,s with "s

    2. It keeps the same order, I don’t see an easy way of re-randomizing the order dynamically. If you’re already thinking of limiting the loop to three cycles, maybe just include the practice subsequence three times in your Sequence (this way the three randomize will generate different orders), and use jump to directly reach the experimental trials for participants who pass, and let participants who fail continue to the next round of practice trials

    3. Yes, I see no technical reason why you couldn’t do that. However some organizations like the IRB have policies regarding participants’ rights to take part in an experiment and/or being compensated for it, so double-check that your setup is consistent with any policies that govern your experiment

    Jeremy

    #7947
    HPI
    Participant

    Dear Jeremy,

    I am back after having run some pilots and I wish to implement some modifications.

    Recap:
    I show to the participant a picture, then a sentence, then a question requesting to rate the sentence that describes the picture, then I load a canvas with 3 emoticons corresponding to 3 keys V (bad) N (so and so) N (good).

    I have a theoretical prediction on how the participant should evaluate each sentence, so in the template, there is a column “Right_Key” which contains the expected key.

    So far I have managed to obtain data on the overall accuracy of responses of the participant.

    I have created a trial before the experiment that sets the counter to 0, when the participant selects a key that matches the expected one, the counter adds 1.

    Running the analysis of the pilot I have noticed that I would like to count and have already the counted variable on one side of the single item:

    If the participant presses the expected key I would like to see a hit (1), if the participant pressed one of the other 2 keys I would like this variable to stay (0).

    So I thought to add a trial before the experimental one, set an “item_score” variable to 0 when there is a success the “item_score” makes +1, I log the value, I set the value again to 0 at the end of the trial.

    This is what I had:

    newTrial("score_experiment_0", 
        newVar("exp_score") // #this is the overall accuracy
        .global()
        .set(0) 
        )  
    
    Template("stimuli.csv", variable =>
        newTrial("experimental_trial",
    
    
    // ....
    
    .test.selected({ V: getImage("inappropriate"), B: getImage("infelicitous"), N: getImage("appropriate") }[variable.Right_Key]) // Increment if correct answer
        .success( getVar("exp_score").set(s_exp=>s_exp+1)) 
    
    // ....
    
    

    at the end when I log all the conditions I added .log("Accuracy", getVar("exp_score"))

    This works.

    Now I want to add the second counter (the new trial is added to the sequence on top):

    newTrial("score_experiment_0", 
        newVar("exp_score")  // #global accuracy
        .global()
        .set(0) 
        )  
        
    newTrial("score_item_0", 
        newVar("item_score") #new variable that must go 0 or 1
        .global()
        .set(0) 
        )  
    
    Template("stimuli.csv", variable =>
        newTrial("experimental_trial",
    
    // ........
    
    .test.selected({ V: getImage("inappropriate"), B: getImage("infelicitous"), N: getImage("appropriate") }[variable.Right_Key]) // Increment if correct answer
        .success( getVar("exp_score").set(s_exp=>s_exp+1)) 
        .and( getVar("item_score").set(sc_i=>sc_i+1))

    Here I tried to set it directly to 1 .set(sc_i=>1)) but it didn’t work, so I chose to go +1 because at trial 1 it’s a 0, it goes 1 then I want to save it and set it back to 0.

    getVar("item_score")
        .log()
        ,
    
    // ...
    
    (getVar("item_score").set(sc_i=>0)).

    It tells me that the variable “item_score” doesn’t exist, (but it does) and doesn’t compute correctly neither the item_score nor the global exp_score like this, so I guess it doesn’t compute correctly .success

    Is there a way to correctly write “more than one action to do after a success?”

    .success — do this; .and —- ; and —

    Or after .success is it possible to have one command?

    ————————————————

    With the same principle, I would like to have in the output the counter of how many V, or B, or N, they clicked, so after the selection, I would like to add

    “if” .test.selected({ V: getImage(“inappropriate”), B: getImage(“infelicitous”), N: getImage(“appropriate”) } “N”) // Increment if the participant presses N

    the variable “count_N”. (getVar(“count_N”).set(sc_i=>sc_i+1)).

    But also in this case I would have to test:
    -if it matches right_key then do +1 on the entire experiment;
    -if it matches right_key then do +1 on the item then set it back to 0;
    -if it matches “N” then do +1 on the entire experiment;
    -if it matches “B” then do +1 on the entire experiment;
    -if it matches “V” then do +1 on the entire experiment;

    after the line .test.selected

    Is it possible to have multiple tests after the selection and save the values of the variables?

    Thanks!

    (then we would like to implement another part of the test measuring a covariate of language proficiency, and I am working on it, but first I would like to implement these changes)

    Thank you for your help!

    HPI

    #7951
    Jeremy
    Keymaster

    Hi,

    I’m not sure I’m following everything, but and does not mean “and do something else,” it is used to write a conjunctive test: reference

    The commands success and failure accept subsequences of commands, separated by commas just like the main sequence of commands, eg:

    .test.selected({ V: getImage("inappropriate"), B: getImage("infelicitous"), N: getImage("appropriate") }[variable.Right_Key])
    .success( 
      getVar("exp_score").set(s_exp=>s_exp+1)
      ,
      getVar("item_score").set(sc_i=>sc_i+1)
    )

    And yes, it is possible to have multiple test commands on the same element:

    .test.selected({ V: getImage("inappropriate"), B: getImage("infelicitous"), N: getImage("appropriate") }[variable.Right_Key])
    .success(
      getVar("exp_score").set(s_exp=>s_exp+1)
      ,
      getVar("item_score").set(sc_i=>sc_i+1)
    )
    .test.selected(getImage("inappropriate")).success( getVar("v_score").set( v=> v+1 ) )
    .test.selected(getImage("infelicitous")).success( getVar("b_score").set( v=> v+1 ) )
    .test.selected(getImage("appropriate")).success( getVar("n_score").set( v=> v+1 ) )

    Note that in this example I assume you have created the Var elements named v_score, b_score and n_score earlier

    Feel free to share a link to your experiment with me if you’d like more assistance, so I can see the code as is, in context

    Jeremy

    #7976
    HPI
    Participant

    Hi,
    thank you for your help with writing several operations after a success. It worked.
    The only thing that took me a while, some try-fail rounds, is the setting of a variable as a definite value (different from 0, and when calling it with “getVar”)
    I wanted to mark whether each trial was correctly answered so I wanted to assign a 1 when it was correct, and a 0 when the response was not correct and I was writing
    success( getVar(“score”).set( v=> 1 ). This wouldn’t work, it worked at the end writing set(1). I thought this syntax was used only in the definition of a variable. But I got it.

    And I thought such a counter would appear as a row in the results after the selection of the response, but I managed to log it at the end so it appears attached as a column.

    So this is solved. Many thanks!

    ————————

    I have to add after the experiment a small test for language proficiency.
    This text is called C-test. There is a text like a piece I show here underneath:

    “It was so easy to get lost in an ancient building”

    That appears to the participants with parts of the words missing:

    “It was so ea__ to get lost in an anc__ buil____”

    The participant has to fill the gaps.

    This type of text has been already implemented on ibex in my university, but with the old Ibex syntax, and I have all my exp in the new syntax, so I would like to adjust the script in the old Ibex to add it to my script with the new syntax.

    There is a function written previously that I don’t know if it exists already in Pcibex, or if I have to add it to my script, in that case, I wanted to double-check with you if it’s ok to declare it in this way.

    function blank(a, b) {
      var sentence = b ? b : a;
       var n = b ? a : null;
    
       var seq = [""];
       var inBlank = false;
      for (var i = 0; i < sentence.length; ++i) {
          var c = sentence.charAt(i)
          if (inBlank) {
               if (c == '_')
                   (seq[seq.length])++;
              else {
                   seq.push(c);
                   inBlank = true;
               }
           }
           else {
               if (c != '_')
                   seq[seq.length-1] += c
              else {
                   seq.push(1);
                   inBlank = true;
               }
           }
       }

    Then the text is called like this:

    ["blank", "Form", blank(""It was so ea__ to get lost in an anc__ buil____"")],

    The texts are obviously not composed just by one sentence but by many in sequence.

    Questions:

    Can I add the function written in this way on top of my script that uses only the new syntax? Should I rewrite the function? I am not sure I have found the documentation on the syntax in the new pcIbex.

    Then I guess I have to make a template in which each text corresponds to a variable, so if it has to appear all in one screen to the participants, if I write it first in excel, each full text should stay in a single cell.

    Then how should I call in the function “blank” to operate on the texts?

    Thank you for your help and for answering my thousands questions!

    HPI

    #7978
    Jeremy
    Keymaster

    Hi,

    The code of the blank function you report seem to be missing a few lines, but if I understand its purpose correctly, you can rewrite it in a more concise way, eg:

    blank = sentence => Object({html: 
        sentence.replace(/_+/g, (t,i)=>`<textarea name='blank${i}' rows=1 cols=${t.length+1} style='max-height: 1.7em'></textarea>`)
    });

    Then you can use it the way you discuss, either creating a Form item using the standard Ibex syntax:

    items = [
        ["blank", "Form", blank("It was so ea__ to get lost in an anc__ buil____")]
    ]

    Or injecting a Form controller inside a PennController trial:

    newTrial("blank", 
        newController("Form", blank("It was so ea__ to get lost in an anc__ buil____"))
            .log()
            .print()
            .wait()
    )

    Jeremy

    #7988
    HPI
    Participant

    Hi,

    thank you! I’ll try what you suggest.

    In this way the script is composed of the practice + the main experiment, now this second part is an independent new small test.

    To save my data, I use the line SendResults(“send”); after the main experiment and I save the practice and the main experiment.

    Is it smarter to add this new small test before the command SendResults(“send”); and save all together, or should I save the two parts of the study in two different moments?

    So I SendResults(“send”); after the main experiment, then launch the new instructions let them do the second task and save again with SendResults(“send”);

    Would I be able to understand it is the same participant who did the main experiment and the c-test in this way? Would I mess around the data adding a second independent part within the same script and saving just once at the end?

    Thank you!
    HPI

    #7989
    HPI
    Participant

    Hi,

    sorry for the double message, now I placed only one “send results” at the end and it seems to work.

    Is it possible to combine the form with the template?

    newTrial("blank", 
        newController("Form", blank("It was so ea__ to get lost in an anc__ buil____"))
            .log()
            .print()
            .wait()
    )

    Because now I get in the result something like:

    blank1 = sy
    blank2 = ient
    blank3 = ding

    I am trying to code in a variable the expected answer so that I can compile the accuracy within the script.

    and then log in the results output a column for each participant the expected output their output and if they match adding up the score?

    I am not sure how to deal with the form in combination with the template.

    Thank you a lot for your help,

    HPI

    #7990
    HPI
    Participant

    Sorry I noticed I didn’t copy the whole function:

    It was like that in the previous script:

    function blank(a, b) {
      var sentence = b ? b : a;
       var n = b ? a : null;
    
       var seq = [""];
       var inBlank = false;
      for (var i = 0; i < sentence.length; ++i) {
          var c = sentence.charAt(i)
          if (inBlank) {
               if (c == '_')
                   (seq[seq.length])++;
              else {
                   seq.push(c);
                   inBlank = true;
               }
           }
           else {
               if (c != '_')
                   seq[seq.length-1] += c
              else {
                   seq.push(1);
                   inBlank = true;
               }
           }
       }
    
      var ihtml = "";
      var bcount = 0;
       for (var i = 0; i < seq.length; ++i) {
           if (typeof(seq[i]) == "number") {
               ++bcount;
               var input = " <input type='text' name='blank-" + bcount + "' size='" + (n ? n : seq[i]) + "'></input> ";
               ihtml += input;
           }
          else {
               ihtml += $("<div>").text(seq[i])[0].innerHTML;
           }
       }
    
       var e = "<p>";
       var validators = { };
      var bcount = 0;
      for (var i = 0; i < seq.length; ++i) {
           if (typeof(seq[i]) == "number") {
               ++bcount;
              e += "<label class='error' for='blank-" + bcount + "'></label>"
             ;
             validators['blank-' + bcount] = function (s) { if (s && !s.match(/^\s*$/)) return true; else return "You must fill in the blank."; }
           }
       }
      e += "</p>"
    
      return {
          html: "<p>" + ihtml + "</p>" + e,
          validators: validators
       };
    }
    #7991
    Jeremy
    Keymaster

    Hi,

    Because now I get in the result something like:

    blank1 = sy
    blank2 = ient
    blank3 = ding

    This would be what you get from the code of the blank function from your last message, right (eg blank-1)? Because the code of the blank function I proposed would look something like blank-12, blank-36 and blank-43 (the numbers correspond to the index in the string of each first _ in a series)

    I am trying to code in a variable the expected answer so that I can compile the accuracy within the script.

    Unless you need to show some feedback based on whether the participant answered accurately, it generally is a better idea to log raw responses and compute accuracy post data-collection. Logging raw responses is always a good idea anyway, and computing accuracy add unnecessary load during runtime

    Now, assuming you always have exactly three textboxes, you could use global Var elements to store their content (by regularly inspecting the HTML elements, eg every 50ms) and log them as extra columns:

    blank = sentence => Object({html: 
        sentence.replace(/_+/g, (t,i)=>`<textarea name='blank${i}' rows=1 cols=${t.length+1} style='max-height: 1.7em'></textarea>`)
    });
    
    newTrial("blank",
        newVar("answer1","").global(),newVar("answer2","").global(),newVar("answer3","").global()
        ,
        newTimer("loop", 50).callback(
            getVar("answer1").set(v=>(document.querySelectorAll("textarea[name^='blank']")[0]||{value:v}).value ),
            getVar("answer2").set(v=>(document.querySelectorAll("textarea[name^='blank']")[1]||{value:v}).value ),
            getVar("answer3").set(v=>(document.querySelectorAll("textarea[name^='blank']")[2]||{value:v}).value )
            ,
            getTimer("loop").start()    
        ).start()
        ,
        newController("Form", blank("It was so ea__ to get lost in an anc__ buil____"))
            .print()
            .wait()
    )
    .log("answer1", getVar("answer1"))
    .log("answer2", getVar("answer2"))
    .log("answer3", getVar("answer3"))

    Or, if you are using Template and have the expected responses in columns named, say, “Correct1,” “Correct2” and “Correct3”:

    Template( row =>
      newTrial("blank",
        newVar("answer1","").global(),newVar("answer2","").global(),newVar("answer3","").global()
        ,
        newTimer("loop", 50).callback(
            getVar("answer1").set(v=>(document.querySelectorAll("textarea[name^='blank']")[0]||{value:v}).value ),
            getVar("answer2").set(v=>(document.querySelectorAll("textarea[name^='blank']")[1]||{value:v}).value ),
            getVar("answer3").set(v=>(document.querySelectorAll("textarea[name^='blank']")[2]||{value:v}).value )
            ,
            getTimer("loop").start()    
        ).start()
        ,
        newController("Form", blank("It was so ea__ to get lost in an anc__ buil____"))
            .print()
            .wait()
        ,
        newVar("correct1").global().set(getVar("answer1")).set( v=>v==row.Correct1 ),
        newVar("correct2").global().set(getVar("answer2")).set( v=>v==row.Correct2 ),
        newVar("correct3").global().set(getVar("answer3")).set( v=>v==row.Correct3 )
      )
      .log("answer1", getVar("answer1"))
      .log("answer2", getVar("answer2"))
      .log("answer3", getVar("answer3"))
      .log("correct1", getVar("correct1"))
      .log("correct2", getVar("correct2"))
      .log("correct3", getVar("correct3"))
    )

    Jeremy

    #7992
    HPI
    Participant

    Hi, thanks, it’s exactly the template in this way

    Template( row =>
    newTrial(“blank”,

    what I wished to do.

    Now that I posted the whole function (in the old syntax) the function with the more compact syntax that you wrote doesn’t need to be modified, right?

    The blank index is correct the way you wrote blank12 ecc.. but because now I have this part of the script after my task is number like blank171… I am understanding now that the item number in the output (like blank17..something here) always corresponds to the order of the input. This is very smart.

    Everybody tells me to code the RT and the accuracy in the data analysis afterward, but I literally just spent the whole night fixing somebody else’s dataset that got messed up in several transformations and file separations. Then merging several datasets has a risk of misplacement, errors that I don’t want to have in my data. 😀

    My philosophy is to start with a dataset that has the relevant info concerning a participant all already there 😀

    So I like to attach to the data the conditions and expected answers and so on…the accuracy.

    Can I impose a restriction on the blanks so that the participant cannot leave it empty, as well as a restriction that the participant cannot write something 20 characters long, I don’t know..to impose a range that the string the participant writes is between 1 and 6 characters long.

    I’ll work on the script with the template,
    Thanks!
    HPI

    #7993
    Jeremy
    Keymaster

    Hi,

    Can I impose a restriction on the blanks so that the participant cannot leave it empty, as well as a restriction that the participant cannot write something 20 characters long, I don’t know..to impose a range that the string the participant writes is between 1 and 6 characters long.

    You could replace the ‘continue’ link of the Form controller with a Button element, and test the content of the Var elements in its wait command:

    newController("Form", blank("It was so ea__ to get lost in an anc__ buil____")).print()
    ,
    newButton("Continue").print().wait(
        getVar("answer1").test.is(v=>v.match(/^\w{1,6}$/))
            .and( getVar("answer2").test.is(v=>v.match(/^\w{1,6}$/)) )
            .and( getVar("answer3").test.is(v=>v.match(/^\w{1,6}$/)) )
            .failure( newText("Please type between 1-6 characters in each box").print() )
    )

    Just make sure you set continueMessage: null on the Form controller, either as a default, or by modifying the first line of blank:

    blank = sentence => Object({continueMessage: null, html: 

    Jeremy

    #8009
    HPI
    Participant

    Hi,

    I just want to signal that lately, PcIbex is not updating the script even if it says it’s saving it. It did it also before, but after a couple of modifications in the script, it would save the latest versions. For 5 or 6 days it hasn’t been completely updating the script and it has been loading previously saved versions.

    Also, other researchers in my university are experiencing this problem.

    Is there anything we can do?

    Thank you!
    HPI

    #8011
    Jeremy
    Keymaster

    Hi,

    This is a known issue, we are working on fixing it. Apologies for the inconvenience

    Jeremy

    #8013
    HPI
    Participant

    Hi,

    thank you for the reply, reuploading the main js file works.

    I am working in this part:

    Template( row =>
      newTrial("blank",
        newVar("answer1","").global(),newVar("answer2","").global(),newVar("answer3","").global()
        ,
        newTimer("loop", 50).callback(
            getVar("answer1").set(v=>(document.querySelectorAll("textarea[name^='blank']")[0]||{value:v}).value ),
            getVar("answer2").set(v=>(document.querySelectorAll("textarea[name^='blank']")[1]||{value:v}).value ),
            getVar("answer3").set(v=>(document.querySelectorAll("textarea[name^='blank']")[2]||{value:v}).value )
            ,
            getTimer("loop").start()    
        ).start()
        ,
        newController("Form", blank("It was so ea__ to get lost in an anc__ buil____"))
            .print()
            .wait()
        ,
        newVar("correct1").global().set(getVar("answer1")).set( v=>v==row.Correct1 ),
        newVar("correct2").global().set(getVar("answer2")).set( v=>v==row.Correct2 ),
        newVar("correct3").global().set(getVar("answer3")).set( v=>v==row.Correct3 )
      )
      .log("answer1", getVar("answer1"))
      .log("answer2", getVar("answer2"))
      .log("answer3", getVar("answer3"))
      .log("correct1", getVar("correct1"))
      .log("correct2", getVar("correct2"))
      .log("correct3", getVar("correct"))
    )

    I am not sure newVar(“correct1”).global().set(getVar(“answer1”)).set( v=>v==row.Correct1 ),

    performs the operation that I want to do.

    I placed in a template the columns with the right answers, one column per answer, and the column name are “ansa_right_blank_1”, “ansa_right_blank_2”, ecc..

    The name of the text is “ansa”, so I named the trial and variables with this label

    I want to do something like test.selected, so if the answer written by the participant matches correct1, a variable should mark the hit (like 1), and a variable should add + 1.

    In the main experiment I have used this strategy: exp score gets the total accuracy, item score marks either 0 or 1.

    .success( 
            getVar("exp_score").set(s_exp=>s_exp+1) 
            ,
            getVar("item_score")
            .set(1)
            )
        .failure(
            getVar("item_score")
            .set(0)
            )

    Can I use something like .test.selected for the answers obtained with the blank function? and then add a calculation like the one above for accuracy?

    newVar("correct1").global().set(getVar("answer1")).set( v=>v==row.Correct1 )
    Does this write in answer1 the answer only if it matches the one in the template?

    the results look like this:

    # 13. ansa_1. (this is answer1 in your script)																					
    # 14. ansa_2.																						
    # 15. ansa_3.																						
    # 16. ansa_right_blank_1. (this is correct1 in your script)																						
    # 17. ansa_right_blank_2.																						
    # 18. ansa_right_blank_3.																						
    # 19. Comments.																						
    1649154382	aaa344f7a0904712475fe5f0de010eb2	PennController	41	0	ansa	NULL	PennController	45	_Trial_	Start	1.64915E+12	poo	ggoa	bbo	false	false	false	NULL				
    1649154382	aaa344f7a0904712475fe5f0de010eb2	PennController	41	0	ansa	NULL	Controller-Form	Form	blank170	poo	1.64915E+12	poo	ggoa	bbo	false	false	false	Any addtional parameters were appended as additional columns				
    1649154382	aaa344f7a0904712475fe5f0de010eb2	PennController	41	0	ansa	NULL	Controller-Form	Form	blank179	ggoa	1.64915E+12	poo	ggoa	bbo	false	false	false	Any addtional parameters were appended as additional columns				
    1649154382	aaa344f7a0904712475fe5f0de010eb2	PennController	41	0	ansa	NULL	Controller-Form	Form	blank186	bbo	1.64915E+12	poo	ggoa	bbo	false	false	false	Any addtional parameters were appended as additional columns

    Thank you!
    HPI

    #8025
    HPI
    Participant

    Hi,

    The original blank function i have copied paste here checked for blank spaces like this
    (s && !s.match(/^\s*$/)) (if i understood correctly this checks that the box has not spaces)

    the one you suggested me test.is(v=>v.match(/^\w{1,6}$/))

    doesn’t consider accented letters and I must allow for accented LATIN and SLAVIC letters.

    If I write a string containing “à” it considers the slot empty and doesn’t let me move forward in the task, and this is a bug.

    Could you suggest how to improve the syntax?

    I went around online to understand how to implement accented letters, but I really don’t get how to combine the syntax “any letter” “any accented letter” “1-6 characters long”.

    I think I should write something like this /^[a-zA-Z\u00C0-\u017F]+$/ but I get errors, I don’t understand the correct way to write this here.

    I was trying for a solution like “doesn’t match empty” as in the original function, but I don’t understand to negate .match

    I managed to set the counter of the previous message.

    Thank you for your help,

    HPI

Viewing 15 posts - 31 through 45 (of 48 total)
  • You must be logged in to reply to this topic.