Jeremy

Forum Replies Created

Viewing 15 posts - 286 through 300 (of 1,522 total)
  • Author
    Posts
  • in reply to: Randomly Shuffle Positions of Elements #9619
    Jeremy
    Keymaster

    Hi Yev,

    Use the Selector element’s shuffle command, as illustrated above and in the tutorial:

    newSelector("images")
    ,
    defaultImage.size(100,100).selector("images")
    ,
    newCanvas("3x3", 300, 300)
      .add(  0,  0,newImage("one.png"))
      .add(100,  0,newImage("two.png"))
      .add(200,  0,newImage("three.png"))
      .add(  0,100,newImage("four.png"))
      .add(100,100,newImage("five.png"))
      .add(200,100,newImage("six.png"))
      .add(  0,200,newImage("seven.png"))
      .add(100,200,newImage("eight.png"))
      .add(200,200,newImage("nine.png"))
      .print()
    ,
    getSelector("images").shuffle().disable()

    Jeremy

    in reply to: Shuffling audio and text elements consistently #9618
    Jeremy
    Keymaster

    Hi Laia,

    You could inject some plain javascript into your code to conditionally reference the first vs the second sentence:

    newTrial("practice",
        oneFirst = (Math.random()>=0.5)
        ,
        newAudio("audio1", "1fishSquareTank.mp3"),
        newAudio("audio2", "2fishRoundTank.mp3"),
        newText("sentence1", "The fish swims in a tank which is perfectly square."),
        newText("sentence2", "The fish swim in a tank which is perfectly round.")
        ,
        newCanvas("frases", 800, 400).print()
        ,
        getText(oneFirst?"sentence1":"sentence2").print(  0,0,getCanvas("frases")),
        getAudio(oneFirst?"audio1":"audio2").play().wait()
        ,
        getText(oneFirst?"sentence2":"sentence1").print(400,0,getCanvas("frases")),
        getAudio(oneFirst?"audio2":"audio1").play().wait()
        ,
        newSelector("choice")
            .add( getText("sentence1") , getText("sentence2")  )
            .log()
            .wait()
    )
    .log("startWith", oneFirst?1:2) // log which sentence came first

    Jeremy

    in reply to: Removing default text when participant enters text #9617
    Jeremy
    Keymaster

    Hi,

    What you describe is the placeholder attribute of the HTML textarea element, and PennController does not provide a direct command to set it, but it actually isn’t that hard to implement:

    newTextInput('text').print()
    ,
    // The bit after the dash ('text') needs to match the name of the TextInput element
    newFunction( ()=>document.querySelector("textarea.PennController-text").placeholder = 'This is the default text.' ).call()
    ,

    Jeremy

    in reply to: Randomization by feature and by item #9616
    Jeremy
    Keymaster

    Hi,

    The columns are not randomized: the features array is randomized, which contains predicates over labels of trials; in effect, it is the order in which the trials are inserted in the sequence that is randomized, not the table or its columns, and not the way the trials are created more generally

    If you want to detect a change in feature upon runtime, you can use a global Var element to remember the value of the Feature column from the trial that was run before the current one, and compare the value of that Var element with the current value of row.Feature: if they are different, it means the current trial is starting a new feature block:

    newTrial( row.Feature + "-" + row.Item ,
      newText("instruct_exerc", "Bitte bewerten Sie, ob beide Tiere gleich gut Verursacher oder Empfänger der Handlung sein können.")
        .css({'font-family': "helvetica"})
        .center()
        .print()
        ,
      newVar("feature")
        .global().test.is( row.Feature ).failure(
          newText("feature_change", "Attention: New Feature ")
            .cssContainer({"margin-top":"2em", "margin-bottom":"2em", 'font-family': "helvetica"})
            .css("font-size", "1.2em").color("Red").bold().center()
            .print()
        )
        .set( row.Feature )
      ,

    Jeremy

    in reply to: About keyresponse in Question #9615
    Jeremy
    Keymaster

    Hi Karen,

    When the Question controller’s as parameter is not an array of strings, but an array of pairs of strings (whose first member represents a key and the second member is the printed answer) you cannot pass a string as hasCorrect: you need to either pass true, in which case it means the first answer is the correct one, or a integer between 0 and the length of the array minus one, so in your case where you have two answers, either 0 (first answer in the array, selectable by pressing F) or 1 (second answer in the array, selectable by pressing J)

    Now, there is a subtlety, which is that values fetched from the table in Template are interpreted as strings by default, so even if you list 0s and 1s in your “Corr” column, they’ll still be interpreted as strings when you reference row.Corr. The solution is to force a coercion into an integer, using parseInt: newController("Question", {q: "Is it reasonable?", as: [["F","reasonable"], ["J","unreasonable"]], hasCorrect: parseInt(row.Corr), randomOrder: false})

    Jeremy

    in reply to: DragDrop features #9602
    Jeremy
    Keymaster

    Note that I found another bug with the suggestion above: creating a second DragDrop element messes with detecting dropping events on it, hence never validating its wait command. So instead of creating two DragDrop elements, one should create and reuse a single one:

    newDragDrop("dragdrop")
        .addDrag(getImage("bear"))
        .addDrop(getCanvas("flowerCV"))
        .wait()
        .removeDrag(getImage("bear"))
        .removeDrop(getCanvas("flowerCV"))
    ,
    // ...
    getDragDrop("dragdrop")
        .addDrag(getCanvas("flowerCV"))
        .addDrop(getCanvas("boxCV"))
        .wait()

    Jeremy

    in reply to: DragDrop features #9601
    Jeremy
    Keymaster

    Simply print the “bear” Image element and the Canvas elements containing the other images on a bigger Canvas element, and then shuffle those:

    newCanvas("mainContainer", 900,300).print()
    ,
    newImage("bear","bear.png").size(100,100).print(0,0,getCanvas("mainContainer")),
    newImage("bearCopy","bear.png").size(100,100).cssContainer("pointer-events","none").css("pointer-events","none")
    ,
    newCanvas("flowerCV", 200,200).add(0,0,newImage("flower","flower.png").size(200,200)).print(300,0,getCanvas("mainContainer"))
    ,
    newCanvas("boxCV", 300,300).add(0,0,newImage("box","box.png").size(300,300)).print(600,0,getCanvas("mainContainer"))
    ,
    newSelector("shuffle").add(getImage("bear"),getCanvas("flowerCV"),getCanvas("boxCV")).shuffle().disable()

    Jeremy

    in reply to: DragDrop features #9599
    Jeremy
    Keymaster

    Hi,

    I just realized I never addressed the previous post, so I will do it now. Unfortunately there is no built-in way to log coordinates in a DragDrop element, but it can be achieved using some javascript. The set command of Var elements accepts javascript functions, so we can create one Var element for each pair of coordinates we want to log:

    newTimer(5000).start()
      .wait()
    ,
    newVar("manXY").set(v=>{ const bcr = getImage("man")._element.jQueryElement[0].getBoundingClientRect(); return bcr.x+';'+bcr.y; }).log(),
    newVar("boyXY").set(v=>{ const bcr = getImage("boy")._element.jQueryElement[0].getBoundingClientRect(); return bcr.x+';'+bcr.y; }).log(),
    newVar("figlistXY").set(v=>{ const bcr = getCanvas("figlist")._element.jQueryElement[0].getBoundingClientRect(); return bcr.x+';'+bcr.y; }).log()
    )

    Now, regarding the linking of two pictures, it should be possible in theory, but I found out there are a few bugs with such chaining in the DragDrop element. We will need a few tricks to work around those bugs, namely we will remove the image of the bear once it’s placed on the flower, and replace it with a copy of it; we will need to retrieve the coordinates of the original image to do that though, which will involve some javascript
    We will also need to have the bear and the flower placed on a Canvas element and make them “transparent” so that the Canvas element can be dragged onto the box:

    ERRATUM: see this post on how to use a single DragDrop element instead

    newText("instructions", "Put the bear on the flower").print()
    ,
    newImage("bear","bear.png").size(100,100).print(),
    newImage("bearCopy","bear.png").size(100,100).cssContainer("pointer-events","none").css("pointer-events","none")
    ,
    newCanvas("flowerCV", 200,200).add(0,0,newImage("flower","flower.png").size(200,200)).print()
    ,
    newCanvas("boxCV", 300,300).add(0,0,newImage("box","box.png").size(300,300)).print()
    ,
    newDragDrop("bearToFlower")
        .addDrag(getImage("bear"))
        .addDrop(getCanvas("flowerCV"))
        .wait()
    ,
    newFunction(()=>new Promise(async r=>{
        const bearBCR = getImage("bear")._element.jQueryElement[0].getBoundingClientRect();
        const flowerBCR = getCanvas("flowerCV")._element.jQueryElement[0].getBoundingClientRect();
        await getCanvas("flowerCV").add(bearBCR.x-flowerBCR.x,bearBCR.y-flowerBCR.y,getImage("bearCopy"))._runPromises();
        r();
    })).call()
    ,
    getImage("bear").hidden().remove(),
    getImage("flower").cssContainer("pointer-events","none")
    ,
    getText("instructions").text("Now put them in the box")
    ,
    newDragDrop("flowerToBox")
        .addDrag(getCanvas("flowerCV"))
        .addDrop(getCanvas("boxCV"))
        .wait()
    

    Let me know if you have questions

    Jeremy

    • This reply was modified 2 years, 8 months ago by Jeremy. Reason: reference to correction below
    in reply to: accidentally deleted result files #9598
    Jeremy
    Keymaster

    Hi,

    If you used the Ibexfarm interface to delete those two files, they were deleted using Perl’s unlink function, so the OS no longer maintains a copy of the files. In that case, you might want to consider using some recovery tools to try and retrieve your files (eg. PhotoRect is a free, cross-platform software that I’ve used with success in the past) — do it as soon as you can though, since when the OS reallocates memory used by the deleted files those can no longer be recovered

    If you deleted them manually using a file browser, maybe the OS sent copies in a recycle bin of some sort

    Jeremy

    in reply to: Trial judgement and present unequal fillers #9597
    Jeremy
    Keymaster

    Hi,

    You cannot use PennController’s test commands to conditionally include an Image element: you are effectively creating an Image element for your filler items too, which don’t have any value for flan_file, resulting in invalid Image elements

    In the script you currently have in your project, your sentence and flanker filler trials actually have nothing in common (as things stand, they do not define pic-spr pairs: there is no pic-spr sequence of commands, unlike in my code above for example; your code currently either includes pic commands or spr commands in a trial) so if that’s the kind of design you are implementing, I would just split the CSV file in two tables and correspondingly use two Template commands to generate the filler trials (and also one Template for your target trials, since they all seem to be SPR’s):

    Template("flanker-fillers.csv", newTrial("fillers", ...pic(row) )
    Template("sentence-fillers.csv", newTrial("fillers", ...spr(row) )
    Template("items-target.csv", newTrial("targets", ...spr(row) )

    Jeremy

    in reply to: About keyresponse in Question #9596
    Jeremy
    Keymaster

    Hi Karen,

    Add randomOrder: false to the Question controller: newController("Question", {q: "Is it reasonable?", as: [["F","reasonable"], ["J","unreasonable"]], hasCorrect: row.Corr, randomOrder: false})

    Jeremy

    in reply to: Randomization by feature and by item #9594
    Jeremy
    Keymaster

    Hi,

    One option is to report the features in your table (as you are currently doing in Features_SemVerMixed.csv) and label your items accordingly: newTrial( row.Feature + "-" + row.Item ,

    Then you can reference the labels in your Sequence command. This would show items 1-to-5 in a fixed order for each feature, with the feature groups of items randomized:

    features = [...new Array(10)].map((v,n)=>startsWith("Feature "+Number(n+1)))
    fisherYates(features)
    Sequence("WelcomeConsent",
        "counter",
        "demographics",   
        "instructions1",
        "exercise",
        "startofexp",
        ...features,
        SendResults(),
        "Bye");

    If you would like to additionally randomize the order of the items within each feature group, replace the first line with:

    features = [...new Array(10)].map((v,n)=>randomize(startsWith("Feature "+Number(n+1))))

    Jeremy

    in reply to: Lists randomization #9593
    Jeremy
    Keymaster

    Hi,

    The script that’s actually running has PennController.ResetPrefix(null) too far down (it should be the first line of the script) and it misses a comma between "demographic" and "instructions" in the Sequence command

    This is most likely due to the Save function bug on the farm: try copying the content of your script file, deleting it from your project and recreating it and pasting the content back in, and it should work

    Jeremy

    in reply to: The new trial page is opening from bottom up #9592
    Jeremy
    Keymaster

    Hi,

    See this post for a solution to this problem

    Jeremy

    in reply to: Logging a Key Press in a Selector #9581
    Jeremy
    Keymaster

    Hi,

    Since your code associates F with the image placed where “File1IDb1” originates, and J with the image placed where “File2IDb1” originates, and since log reports the result of shuffle in the Comments column, you can technically retrieve the key that was pressed from the results file. For example, from this line I can determine that I pressed J, since I selected the option that is listed second in the last column (File1IDb1):

    1666024185 REDACTED PennController 0 0 unlabeled NULL Selector selection1 Selection File1IDb1 1666024185448 File2IDb1;File1IDb1

    That being said, you can still directly log which key was pressed using a Key element in parallel to the Selector element:

    newKey("FJ").log("last")
    ,
    newSelector("selection1")
        .disableClicks()
        .add( getImage("File1IDb1") , getImage("File2IDb1") )
        .shuffle()
        .keys("F","J")
        .wait()
        .log()
    ,
    getKey("FJ").disable()

    Jeremy

Viewing 15 posts - 286 through 300 (of 1,522 total)