Choosing subet of items to present

PennController for IBEX Forums Support Choosing subet of items to present

Viewing 15 posts - 16 through 30 (of 56 total)
  • Author
    Posts
  • #6203
    Jeremy
    Keymaster

    Hi Maria,

    Based on your previous messages, I think you would do something like this for your specific design:

    alt = randomize("alt")
    non = randomize("non")
    fil = randomize("fil")
    
    picked_alt = pick(alt, 29)
    picked_non = pick(non, 17)
    picked_fil = pick(fil, 18)
    
    repeat_alt = pick(randomize(picked_alt), 15)
    repeat_non = pick(randomize(picked_non), 5)
    repeat_fil = pick(randomize(picked_fil), 10)
    
    Sequence( 
      "intro",
      rshuffle(picked_alt, picked_non, picked_fil),
      "transition",
      rshuffle(
        repeat_alt, repeat_non, repeat_fil, 
        pick(alt,15), pick(non,5), pick(fil,5) // Don't know how many fillers are left
      )
    )
    
    
    newTrial("intro", newVar("phase", "training").global() )
    newTrial("transition", getVar("phase").set("test") )
    
    
    const alt_training_trial = row => [
      // code your 'alt' training trials here
    ]
    const non_training_trial = row => [
      // code your 'non' training trials here
    ]
    const fil_training_trial = row => [
      // code your 'fil' training trials here
    ]
    
    
    const alt_test_trial = row => [
      // code your 'alt' test trials here
    ]
    const non_test_trial = row => [
      // code your 'non' test trials here
    ]
    const fil_test_trial = row => [
      // code your 'fil' test trials here
    ]
    
    
    Template( "alt_table , row =>
      newTrial( "alt" ,
        getVar("phase").test.is("training")
            .success( ...alt_test_trial(row) )
            .failure( ...alt_training_trial(row) ) 
      )
      .log("phase", getVar("phase") )
      // You might want to add more logs
    )
    Template( "non_table , row =>
      newTrial( "non" ,
        getVar("phase").test.is("training")
            .success( ...non_test_trial(row) )
            .failure( ...non_training_trial(row) ) 
      )
      .log("phase", getVar("phase") )
      // You might want to add more logs
    )
    Template( "fil_table , row =>
      newTrial( "fil" ,
        getVar("phase").test.is("training")
            .success( ...fil_test_trial(row) )
            .failure( ...fil_training_trial(row) ) 
      )
      .log("phase", getVar("phase") )
      // You might want to add more logs
    )

    I didn’t test this code, but hopefully it should give you the idea

    Let me know if you have any questions

    Jeremy

    #6206
    Maria Evjen
    Participant

    Hi again,

    Thank you for your reply, it was very helpful! When I run my experiment now, it seems from the Sequence function of the Debugger that the script is successful in choosing the right number of trials for the three different categories in both the training and the testing. It also seems like it chooses the right number of repeat and new items.

    However, the training and test trials are not actually showing up on the screen when I run the experiment. My intro, pause and end trials are showing as normal, but for the training and the testing, only the progress bar is showing up on the screen. I can however see the trials in the Sequence of the Debugger and skip to the different trials through “Reach”, but the stimuli are not showing. When I run my trials outside the const format you suggested, they are running as normal, but when I insert them in the code you suggested above, the stimuli are not shown in the trials. Here is an example of my code inside the const format if that helps with identifying the problem:

    const alt_training_trial = row => [
        Template( defaultTable.filter(r => r.Type=="alt" ),
    
        variable => 
        
        newTrial( "alt",
            newTimer(500)
                .start()
                .wait()
            ,
            newImage("sg_picture", variable.SgPictureFile)
                .size(200,200)
                .print()
            ,
            newTimer(200)
                .start()
                .wait()
            ,
            newAudio("sg_voicing", variable.SgVoicingFile)
                .play()
            ,
            newTimer(1500)
                .start()
                .wait()
            ,
            getImage("sg_picture")
                .remove()
            ,
            newTimer(1000)
                .start()
                .wait()
            ,
            newImage("pl_picture", variable.PlPictureFile)
                .size(300,200)
                .print()
            ,
            newTimer(200)
                .start()
                .wait()
            ,
            newAudio("pl_voicing", variable.PlVoicingFile)
                .play()
            ,
            newTimer(2000)
                .start()
                .wait()
            ,
            getImage("pl_picture")
                .remove()
            ,
            newTimer(200)
                .start()
                .wait()
            ,
            newButton("Neste")
                .print()
                .wait()
        )
        )
    ]

    Maria

    #6210
    karmacoma
    Participant

    Hi Jeremy,

    I tried the Pick() function and it worked well only when I randomized the set. That is, without the randomization (I want each stimulus to be picked only once), I got the error “First argument of pick cannot be a plain string”. Could you let me know how to fix this?

    Thank you!

    #6211
    Jeremy
    Keymaster

    Sorry, I realize now that I wasn’t very clear when I typed // code your '...' trials here. If you look back at this previous message, you’ll notice that the content of those const variables, ie. what goes inside the [ ] brackets, does not contain Template or newTrial, but only what normally goes inside the parentheses of newTrial.

    So in this specific case, you should have:

    const alt_training_trial = variable => [
      newTimer(500)
          .start()
          .wait()
      ,
      newImage("sg_picture", variable.SgPictureFile)
          .size(200,200)
          .print()
      ,
      newTimer(200)
          .start()
          .wait()
      ,
      newAudio("sg_voicing", variable.SgVoicingFile)
          .play()
      ,
      newTimer(1500)
          .start()
          .wait()
      ,
      getImage("sg_picture")
          .remove()
      ,
      newTimer(1000)
          .start()
          .wait()
      ,
      newImage("pl_picture", variable.PlPictureFile)
          .size(300,200)
          .print()
      ,
      newTimer(200)
          .start()
          .wait()
      ,
      newAudio("pl_voicing", variable.PlVoicingFile)
          .play()
      ,
      newTimer(2000)
          .start()
          .wait()
      ,
      getImage("pl_picture")
          .remove()
      ,
      newTimer(200)
          .start()
          .wait()
      ,
      newButton("Neste")
          .print()
          .wait()
    ]

    With this corresponding Template command further down in your script (I’m assuming you’ve also defined const alt_test_trial following the same schema as above):

    Template( defaultTable.filter(r => r.Type=="alt" ) , row =>
      newTrial( "alt" ,
        getVar("phase").test.is("training")
            .success( ...alt_test_trial(row) )
            .failure( ...alt_training_trial(row) ) 
      )
      .log("phase", getVar("phase") )
      // You might want to add more logs
    )

    Let me know if you have questions

    Jeremy

    #6212
    Jeremy
    Keymaster

    If you don’t use randomize, you need to use seq to convert the label string into a sequence of trials. Then, pick will always pick the first trial(s) in that sequence, because you won’t have applied randomization first.

    The number of trials you pick is determined by the number you pass to pick and is not related to whether you randomized the trials or not. So if you do this:

    trials = seq("trials")
    Sequence( pick(trials,1), "break", pick(trials,1), "break", pick(trials,1) )
    
    newTrial("trials", newButton("Trial 1").print().wait() )
    newTrial("trials", newButton("Trial 2").print().wait() )
    newTrial("trials", newButton("Trial 3").print().wait() )
    
    newTrial("break", newButton("Break").print().wait() )

    You’ll always see Trial 1 first, then the break trial, then Trial 2, then the break trial again, and finally Trial 3. If you replaced seq with randomize in the code above, you’d still only have one trial before/after the break trials, but the order would be random, eg. Trial 3 – Break – Trial 1 – Break – Trial 2

    Jeremy

    #6213
    karmacoma
    Participant

    thank you jeremy – this is very helpful 🙂

    #6224
    Maria Evjen
    Participant

    Hi again!

    Thank you so much, the stimuli are showing now! But for some reason, it seems like parts of the code in my test trials is not running now, even though it was working outside the const format. Here is an example of my test trials:

    const alt_test_trial = variable => [
        newTimer(500)
            .start()
            .wait()
        ,
        newImage("pl_picture", variable.PlPictureFile)
            .size(300,200)
            .print()
        ,
        newTimer(200)
            .start()
            .wait()
        ,
        newAudio("pl_voicing", variable.PlVoicingFile)
            .play()
        ,
        newTimer(2000)
            .start()
            .wait()
        ,
        getImage("pl_picture")
            .remove()
        ,
        newImage("sg_picture", variable.SgPictureFile)
            .size(200,200)
            .print()
        ,
        newTimer(200)
            .start()
            .wait()
        ,
        newAudio("sg_voicing", variable.SgVoicingFile)
            .play()
        ,
        newTimer(1500)
            .start()
            .wait()
        ,
        newAudio("sg_devoicing", variable.SgDevoicingFile)
            .play()
        ,
        newSelector("target")
            .add( getAudio("sg_voicing") , getAudio("sg_devoicing") )
            .shuffle()
            .keys(          "1"    ,          "2"   )
            .log()
            .wait()
        ,
        newTimer(500)
            .start()
            .wait()
    .log( "sg_picture", variable.SgPictureFile )
    .log("Item", variable.Item)
    ]

    The problem appears to be with getImage(“pl_picture”).remove() and with the shuffle command in the Selector. When I run the experiment, I first want my plural audio and image to be shown before the image will be removed and the singular audio and image will be shown. As it is now, the plural image is not removed and the singular image is just added below the plural image. In addition, it seems like my sg_voicing and sg_devoicing audio files are not being shuffled in the Selector, as the sg_voicing file always ends up being heard first. Also, when I run my experiment and make sure to consistently choose the sg_voicing file, my results file nevertheless says that I have chosen sg_devoicing a lot of the time. I therefore think there must be something wrong with the key assignment and/or the shuffle command in the Selector element.

    I also realised that I have one more design feature in my experiment that I’m not quite sure how to implement. In my testing phase, I would like to have 75% of the trials with a plural trigger and a singular target and 25% of the trials with a singular trigger and a plural target. The example above is of the former type, and I figure that I can make corresponding trials of the latter type by just switching the variables. Then I can define the plural trigger trials as const alt_test_trial_pl and the singular trigger trials as const alt_test_trial_sg for example. But from there on I am stuck, is there any way to implement these two test trial types into the Templates you have suggested?

    Sorry for bombarding you with lots of questions, I really appreciate all your help!

    Maria

    #6225
    Jeremy
    Keymaster

    Hi Maria,

    I’m not sure what is happening with the picture not disappearing from the page: when I test your code, the picture always disappears as it should. I could take a closer look if you sent me a link to your experiment at support@pcibex.net

    The Selector element doesn’t quite work the way you’re using it, because PennController trials execute their script in a linear top-down order: your script runs play on the sg_voicing Audio element first, then it later runs play on the sg_devoicing Audio element, and only after that does it reach the shuffle command of the Selector element, but by then the audios have already played. As a result, all your trials will play sg_voicing first and sg_devoicing second.

    Another important point to note is that using shuffle and then keys will result in a non-deterministic association order-wise. See the command’s documentation page for more detail.

    What you can do however is test the index of the Selector’s elements after shuffling, and decide which to play first based on that, and also properly associate the keys depending on which is first and which is second. Here is a proposal (see notes below):

    const alt_test_trial = variable => [
        newTimer(500)
            .start()
            .wait()
        ,
        newImage("pl_picture", variable.PlPictureFile)
            .size(300,200)
            .print()
        ,
        newTimer(200)
            .start()
            .wait()
        ,
        newAudio("pl_voicing", variable.PlVoicingFile)
            .play()
        ,
        newTimer(2000)
            .start()
            .wait()
        ,
        getImage("pl_picture")
            .remove()
        ,
        newImage("sg_picture", variable.SgPictureFile)
            .size(200,200)
            .print()
        ,
        newTimer(200)
            .start()
            .wait()
        ,
        newAudio("sg_voicing", variable.SgVoicingFile),
        newAudio("sg_devoicing", variable.SgDevoicingFile)
        ,
        newSelector("target")
            .log()
            .add( getAudio("sg_voicing"),getAudio("sg_devoicing") )
            .shuffle()
            .test.index( getAudio("sg_voicing"), 0 )
            .success(
                getAudio("sg_voicing").play().wait(),
                getAudio("sg_devoicing").play().wait(),
                getSelector("target").keys("1","2").wait()
            )
            .failure( 
                getAudio("sg_devoicing").play().wait(),
                getAudio("sg_voicing").play().wait(),
                getSelector("target").keys("2","1").wait()
            )
        ,
        newTimer(500)
            .start()
            .wait()
    ]

    As you can see, I use test.index to see which audio occupies the Selector’s first slot after shuffling, and I accordingly play them in that order, and associate the 1 and 2 keys relative to that order too. Another thing you’ll note is that I use wait on the Audio elements rather than creating a Timer element of a given duration. Of course feel free to go back to the Timer method if that’s more appropriate to your design’s needs.

    One other thing: your last two log commands should attach to the closing parenthesis of newTrial, so they cannot be part of those const definitions. Instead, they should go directly inside the Template command, between its closing parenthesis and that of newTrial (see example below)

    Regarding the 75-25 split in your testing trials, you cannot assign them different labels for the same reason that you couldn’t assign different labels to your training and testing trials: you generate them all from the same rows, and the distribution of your trial types takes scope over all of them. If you were to break them into different labels (ie. different Template/newTrial commands) you would break the solution we’ve come up with to deal with the dependency between training and testing trials.

    The solution I’ll propose here is similar to what we did for testing vs training: creating a global Var element to switch between types of trials. In this case, we’ll switch between singular target and plural target. In order to have 25% of the trials with a singular target and 75% of them with a plural target, we’ll use pick twice on the set of all the testing trials, once with a 25% proportion and once with a 75% proportion, and we’ll precede the trials from each subset with another trial switching to singular or plural target. Here is how to do that, illustrated with “alt” items only:

    alt = randomize("alt")
    picked_alt = pick(alt, 29)
    repeat_alt = pick(randomize(picked_alt), 15) // 15 testing items shown in training
    new_alt = pick(alt, 15) // 15 new trials in testing
    testing_alt = randomize(seq(repeat_alt,new_alt)) // Merge and randomize the 30 test trials
    
    Sequence( 
      "intro",
      rshuffle(picked_alt),
      "transition",
      rshuffle(
        randomize(seq( 
            // Pick 22/30 test trials (~75%) and precede with pl
            precedeEachWith("plTarget", pick(testing_alt, 22) ),
            // Pick 8/30 test trials (~25%) and precede with sg
            precedeEachWith("sgTarget", pick(testing_alt, 8) ) 
        ))
      )
    )
    
    // Minimal example showing how to test "target"
    const alt_test_trial = variable => [ 
        getVar("target").test.is("pl")
            .success( newText("Plural").print() )
            .failure( newText("Singular").print() )
        ,
        newText("Test trial").print()
        ,
        newButton("Next").print().wait() 
    ]
    // Minimal example showing the absence of "target" in training
    const alt_training_trial = variable => [ 
        newText("Training trial").print()
        ,
        newButton("Next").print().wait() 
    ]
    
    // Make sure to define "target" in intro
    newTrial("intro", 
        newVar("phase", "training").global() ,
        newVar("target").global() ,
        newButton("Start").print().wait()
    )
    
    // Each trial sets "target" to the appropriate value
    newTrial("plTarget", getVar("target").set("pl") )
    newTrial("sgTarget", getVar("target").set("sg") )
    
    newTrial("transition", getVar("phase").set("test") )
    
    // This is a minimal example too
    Template( row => 
      newTrial( "alt" ,
        getVar("phase").test.is("training")
            .success( ...alt_training_trial(row) )
            .failure( ...alt_test_trial(row) )
      )
      .log( "Item" , row.Item )
    )

    I must say your design is particularly challenging, with all those distributional requirements! Let me know if you have questions

    Jeremy

    • This reply was modified 3 years, 5 months ago by Jeremy.
    #6232
    Maria Evjen
    Participant

    Hi!

    Thank you, I have e-mailed you a link to my experiment! And yes, I am realising that my experiment is quite difficult to code, I really couldn’t have done it without all your help!

    The precedeEachWith solution works great, but I’m having difficulties with the Selector in the test trials. I implemented your code above like this:

    const alt_test_trial = variable => [
        getVar("target").test.is("sg")
            .success( 
                newTimer(500)
                    .start()
                    .wait()
                ,
                newImage("pl_picture", variable.PlPictureFile)
                    .print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                newAudio("pl_voicing", variable.PlVoicingFile)
                    .play()
                ,
                newTimer(2000)
                    .start()
                    .wait()
                ,
                getImage("pl_picture")
                    .remove()
                ,
                newImage("sg_picture", variable.SgPictureFile)
                    .print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                newAudio("sg_voicing", variable.SgVoicingFile)
                ,
                newAudio("sg_devoicing", variable.SgDevoicingFile)
                ,
                newSelector("target")
                    .log()
                    .add( getAudio("sg_voicing"),getAudio("sg_devoicing") )
                    .shuffle()
                    .test.index( getAudio("sg_voicing"), 0 )
                    .success(
                        getAudio("sg_voicing").play().wait(),
                        getAudio("sg_devoicing").play().wait(),
                        getSelector("target").keys("1","2").wait()
                    )
                    .failure( 
                        getAudio("sg_devoicing").play().wait(),
                        getAudio("sg_voicing").play().wait(),
                        getSelector("target").keys("2","1").wait()
                    )
                ,
                newTimer(500)
                    .start()
                    .wait()
            )
            .failure( 
                newTimer(500)
                    .start()
                    .wait()
                ,
                newImage("sg_picture", variable.SgPictureFile)
                    .print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                newAudio("sg_voicing", variable.SgVoicingFile)
                    .play()
                ,
                newTimer(2000)
                    .start()
                    .wait()
                ,
                getImage("sg_picture")
                    .remove()
                ,
                newImage("pl_picture", variable.PlPictureFile)
                    .print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                newAudio("pl_voicing", variable.PlVoicingFile)
                ,
                newAudio("pl_devoicing", variable.PlDevoicingFile)
                ,
                newSelector("target")
                    .log()
                    .add( getAudio("pl_voicing"),getAudio("pl_devoicing") )
                    .shuffle()
                    .test.index( getAudio("pl_voicing"), 0 )
                    .success(
                        getAudio("pl_voicing").play().wait(),
                        getAudio("pl_devoicing").play().wait(),
                        getSelector("target").keys("1","2").wait()
    
                    )
                    .failure( 
                        getAudio("pl_devoicing").play().wait(),
                        getAudio("pl_voicing").play().wait(),
                        getSelector("target").keys("2","1").wait()
    
                    )
            )
    ]

    In addition to the .remove() problem, it appears that the script can’t play the sg_voicing files and the pl_voicing files when these are targets. When I run the experiment, the trigger audio file is played, but both when the target is singular and when it is plural, the voicing files are not played. The sg_devoicing and pl_devoicing files, on the other hand, are played. There are some exceptions though, so that sometimes, it appears randomly, both the voicing and the devoicing file are played, or neither are played, but this seems to be rare. At times more than one item is shown (both images and audio) in one trial as well. When there is a file that can’t be played, the selection with the keys does not work either, I assume this is because the trial is stuck and is not getting to the key assignment part. Do you know why this could be?

    Thanks again!

    Maria

    #6233
    Jeremy
    Keymaster

    Hi Maria,

    I think the two problems are related. All the commands in the success and failure blocks of a test are still part of the trial, even though upon runtime only one of the two blocks will effectively be run. Accordingly, all the new* declarations from either block are processed, which means that the code you’ve posted creates duplicates of sg_picture, pl_picture, sg_voicing and pl_voicing. That’s why when you try to .remove a picture, it can sometimes point to the wrong one (the one from the other block) and fail to effectively take it off the page. Regarding the Audio elements, I’m not sure why you see this specific problem, but I suspect problems will go away if you avoid creating the element twice.

    Here is what your code looks like after factoring the creation of the elements:

    const alt_test_trial = variable => [
        newImage("sg_picture", variable.SgPictureFile),
        newImage("pl_picture", variable.PlPictureFile),
        newAudio("sg_voicing", variable.SgVoicingFile),
        newAudio("pl_voicing", variable.PlVoicingFile)
        ,
        getVar("target").test.is("sg")
            .success( 
                newTimer(500)
                    .start()
                    .wait()
                ,
                getImage("pl_picture").print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                getAudio("pl_voicing").play()
                ,
                newTimer(2000)
                    .start()
                    .wait()
                ,
                getImage("pl_picture").remove()
                ,
                getImage("sg_picture").print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                newAudio("sg_devoicing", variable.SgDevoicingFile)
                ,
                newSelector("target")
                    .log()
                    .add( getAudio("sg_voicing"),getAudio("sg_devoicing") )
                    .shuffle()
                    .test.index( getAudio("sg_voicing"), 0 )
                    .success(
                        getAudio("sg_voicing").play().wait(),
                        getAudio("sg_devoicing").play().wait(),
                        getSelector("target").keys("1","2").wait()
                    )
                    .failure( 
                        getAudio("sg_devoicing").play().wait(),
                        getAudio("sg_voicing").play().wait(),
                        getSelector("target").keys("2","1").wait()
                    )
                ,
                newTimer(500)
                    .start()
                    .wait()
            )
            .failure( 
                newTimer(500)
                    .start()
                    .wait()
                ,
                getImage("sg_picture").print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                getAudio("sg_voicing").play()
                ,
                newTimer(2000)
                    .start()
                    .wait()
                ,
                getImage("sg_picture").remove()
                ,
                getImage("pl_picture").print()
                ,
                newTimer(200)
                    .start()
                    .wait()
                ,
                newAudio("pl_devoicing", variable.PlDevoicingFile)
                ,
                newSelector("target")
                    .log()
                    .add( getAudio("pl_voicing"),getAudio("pl_devoicing") )
                    .shuffle()
                    .test.index( getAudio("pl_voicing"), 0 )
                    .success(
                        getAudio("pl_voicing").play().wait(),
                        getAudio("pl_devoicing").play().wait(),
                        getSelector("target").keys("1","2").wait()
    
                    )
                    .failure( 
                        getAudio("pl_devoicing").play().wait(),
                        getAudio("pl_voicing").play().wait(),
                        getSelector("target").keys("2","1").wait()
    
                    )
            )
    ]

    Don’t forget to also update the other const declarations along the same lines, and don’t hesitate to ask questions

    Jeremy

    #6238
    Maria Evjen
    Participant

    Hi Jeremy,

    I see, that makes sense! I implemented the code above, but I am still having some issues. Now the pictures aren’t showing at all and both the trigger audio file and the target voicing audio file are not playing. Under the Error tab of the Debugger, I am getting the same errors as before saying “No audio to play for element ;sg_voicing” or “No audio to play for element ;pl_voicing” for each test trial. In some trials, the devoicing file is not played either, and as before, the Selector is not working either.

    When I was playing around with it trying to see if I needed to change something, I copied the newAudio and newImage files to the templates in addition to having them in the const declarations like this to see if it helped:

    Template(defaultTable.filter(r => r.Type=="alt" ), row =>
        newTrial( "alt" ,
        newImage("sg_picture", variable.SgPictureFile),
        newImage("pl_picture", variable.PlPictureFile),
        newAudio("sg_voicing", variable.SgVoicingFile),
        newAudio("pl_voicing", variable.PlVoicingFile),
            getVar("phase").test.is("training")
                .success( ...alt_training_trial(row) )
                .failure( ...alt_test_trial(row) )
        )
        .log("phase", getVar("phase") )
        .log( "sg_picture", row.SgPictureFile )
        .log("Item", row.Item)
    )

    When I did this, the test trials ran as they should with both pictures showing, the first picture being removed, and all the sound files playing, but the Selector did not work for the plural target trials. Also, this added the .remove() problem to the training trials for some reason. I don’t know if this helps to figure out what the problem is, but I figured I would include it nevertheless.

    Thanks again!

    Maria

    #6240
    Jeremy
    Keymaster

    Hi Maria,

    I had completely lost sight of the fact that in addition to the test on target, each of your trials also tests phase, and what I said above applies to this test too, because it’s a .test command again: all the new* elements are created upon runtime, no matter whether the trial runs as training vs test or sg_target vs pl_target. So what you did is the right thing to do: create the elements before any test and make sure to only use get* in your const declarations (with the single exceptions of sg_devoicing and pl_devoicing, which are only present in test-sg_target and test-pl_target, respectively).

    For the same reason, you need to factor newSelector("target") because otherwise you would be creating it twice. Another thing about the Selector element, I’d advise renaming it choice for example, because you already have a Var element named target and even though multiple elements of different types sharing a single name is not a fatal configuration, it’s still better practice to use different names.

    Also correct me if I’m wrong, but taking a closer look at your experiment’s script from the link you shared with me, you are using the exact same code for all three types of trials (alt, non, fil), to the letter. The way I understand it, the only differences between those three types of trials lie in what is specified in the table, ie. the nature of the pictures and audios. But the trial structure is exactly the same across all three trial types. Is that right? If so, you don’t need to triple all your Template and const declarations, you can do it just once, and simply label your trials by looking up the Type column of your table.

    See how much shorter your code becomes:

    const training_trial = variable => [
        newTimer(500).start().wait()
        ,
        getImage("sg_picture").print()
        ,
        newTimer(200).start().wait()
        ,
        getAudio("sg_voicing").play()
        ,
        newTimer(1500).start().wait()
        ,
        getImage("sg_picture").remove()
        ,
        newTimer(1000).start().wait()
        ,
        getImage("pl_picture").print()
        ,
        newTimer(200).start().wait()
        ,
        getAudio("pl_voicing").play()
        ,
        newTimer(2000).start().wait()
        ,
        getImage("pl_picture").remove()
        ,
        newTimer(200).start().wait()
    ]
    
    const test_trial = variable => [
        newSelector("choice").log()
        ,
        getVar("target").test.is("sg")
            .success( 
                newTimer(500).start().wait()
                ,
                getImage("pl_picture").print()
                ,
                newTimer(200).start().wait()
                ,
                getAudio("pl_voicing").play()
                ,
                newTimer(2000).start().wait()
                ,
                getImage("pl_picture").remove()
                ,
                getImage("sg_picture").print()
                ,
                newTimer(200).start().wait()
                ,
                newAudio("sg_devoicing", variable.SgDevoicingFile)
                ,
                getSelector("choice")
                    .add( getAudio("sg_voicing"),getAudio("sg_devoicing") )
                    .shuffle()
                    .test.index( getAudio("sg_voicing"), 0 )
                    .success(
                        getAudio("sg_voicing").play().wait(),
                        getAudio("sg_devoicing").play().wait(),
                        getSelector("choice").keys("1","2").wait()
                    )
                    .failure( 
                        getAudio("sg_devoicing").play().wait(),
                        getAudio("sg_voicing").play().wait(),
                        getSelector("choice").keys("2","1").wait()
                    )
                ,
                newTimer(500).start().wait()
            )
            .failure( 
                newTimer(500).start().wait()
                ,
                getImage("sg_picture").print()
                ,
                newTimer(200).start().wait()
                ,
                getAudio("sg_voicing").play()
                ,
                newTimer(2000).start().wait()
                ,
                getImage("sg_picture").remove()
                ,
                getImage("pl_picture").print()
                ,
                newTimer(200).start().wait()
                ,
                newAudio("pl_devoicing", variable.PlDevoicingFile)
                ,
                getSelector("choice")
                    .add( getAudio("pl_voicing"),getAudio("pl_devoicing") )
                    .shuffle()
                    .test.index( getAudio("pl_voicing"), 0 )
                    .success(
                        getAudio("pl_voicing").play().wait(),
                        getAudio("pl_devoicing").play().wait(),
                        getSelector("choice").keys("1","2").wait()
    
                    )
                    .failure( 
                        getAudio("pl_devoicing").play().wait(),
                        getAudio("pl_voicing").play().wait(),
                        getSelector("choice").keys("2","1").wait()
    
                    )
            )
    ]
    
    Template( row =>
        newTrial( row.Type ,
            newImage("sg_picture", row.SgPictureFile),
            newImage("pl_picture", row.PlPictureFile),
            newAudio("sg_voicing", row.SgVoicingFile),
            newAudio("pl_voicing", row.PlVoicingFile)
            ,
            getVar("phase").test.is("training")
                .success( ...training_trial(row) )
                .failure( ...test_trial(row) )
        )
        .log("phase", getVar("phase") )
        .log("sg_picture", row.SgPictureFile )
        .log("Item", row.Item)
    )

    Notice how you don’t need to filter your table at all, but the trials are now labeled row.Type, which ensures that you’ll still end up with trials labeled alt, some labeled fil and some labeled non, based on your table’s Type column.

    I tested this code myself, and the whole experiment ran smoothly. I think we finally got there, but let me know if you have questions

    Jeremy

    #6253
    Maria Evjen
    Participant

    Hi Jeremy,

    Yes, it works perfectly now, thank you so much! And you are right that my alt, non and fil trials all follow the same template, so the way you shortened the script works great.

    I really can’t thank you enough for all your help, you are a lifesaver!

    All the best,
    Maria

    #6796
    apspj
    Participant

    Hi,

    I’m very new to PCIbex and so far I have managed well but got stuck in randomizing.

    I have 8 conditions and 4 items manipulated according to each condition + 5 types of fillers:
    cond item sentence
    A 1 …
    A 2 …
    A 3 …
    A 4
    B 1
    B 1
    B 2
    B 3
    B 4

    filler-1 1

    I would like each participant to randomly see 2 experimental items of each condition and 2 fillers in the following sequence: 1 exp item + 2 fillers, 1 exp item + 2 fillers… I wonder if I could create a subset like this that would also be randomized among participants.

    Thank you,

    Ana.

    #6798
    Jeremy
    Keymaster

    Hi Ana,

    If I understand you correctly, your cond column will go from A through H (8 conditions) with 4 rows for each letter (4 items).

    What I’m not clear about are your fillers: does your cond column go from filler-1 through filler-5 (5 types of fillers), with 4 rows for each one again (as hinted at by the repeated “1” in your example)?

    The other thing I am confused about is how you get 2 fillers between each experimental item, when you run a total of 2*8 = 16 experimental items while you have defined 5*4 = 20 filler items: if you want 2 fillers between each of the 16 experimental items (and assuming you don’t want to repeat any filler) then you will need a total of at least 15*2 = 30 fillers items (if you do not run another 2 filler items after the last experimental item)

    Maybe you meant “2 exp item + 2 fillers,” in which case you would need between 7*2 = 14 and 8*2 = 16 fillers items, so now you have defined too many: would you randomly pick 14 or 16 fillers out of the 20? This is what I will describe here anyway

    So what I would do is label the trials generated from your table by their cond (and item) columns, so you can refer to “A”, “B”, etc. and randomly pick 2 of each when building your sequence. Randomizing a set of labeled trials is pretty straightforward, for example you can randomize all the trials who label starts with A- with randomize(startsWith("A-")). In order to pick 2 trials out of this set, you will need the function pick defined in this thread, then you can simply do pick( randomize(startsWith("A-")) , 2 ). Finally, you can store all your pairs of trials in an array and shuffle the array to run the pairs in a random order:

    conditions = [
        pick(randomize(startsWith("A-")), 2),
        pick(randomize(startsWith("B-")), 2),
        // etc.
    ]
    .sort( ()=>Math.random()-0.5 ) // shuffle
    

    Here is a project that implements this idea: https://farm.pcibex.net/r/GtBCVh/

    Let me know if you have questions

    Jeremy

Viewing 15 posts - 16 through 30 (of 56 total)
  • You must be logged in to reply to this topic.