Forum Replies Created
-
AuthorPosts
-
March 28, 2022 at 9:29 am in reply to: html layout/event times/selector vs. scale/ compatibility #7978
Jeremy
KeymasterHi,
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
Jeremy
KeymasterHi Larissa,
One issue is that you have at least one case where the
log
command of the Key element is missing"all"
(at least in the current code at https://farm.pcibex.net/r/XSJAnP/, where it concerns the trials labeled “trial_1_no_cue_DOWN”)In the absence of a keypress, the line will have
Key
as its parameter instead ofPressedKey
,NA
as its value andNever
in the EventTime column. Sofilter(Parameter %in% c("Key","PressedKey")) %>%
will exclude those lines where the participant never pressed a key. Try replacing it withfilter(Parameter %in% c("Key","PressedKey","Key")) %>%
I’m not sure how to handle the block issue for now. You are correct: having
NA
s in place of timestamps messes with the block column and will assign block 0 to those NA rows. One solution would be to use the linear order of the rows to assign blocks rather than just the EventTime column, but I can’t think of an immediate way of doing it off the top of my headJeremy
Jeremy
KeymasterHi Sharon,
Just refer to the column of your table in the
test
command:Template( "table.csv" , row => newTrial( newText("Press A or B").print() , newKey("AB") .wait() .test.pressed( row.Correct ) .success( newText("Correct, the answer is "+row.Correct+"!").print() ) .failure( newText("No, the answer was "+row.Correct+".").print() ) , newButton("Next").print().wait() ) )
Jeremy
Jeremy
KeymasterYes: if you want to reset both Var elements before going back to the beginning of the p_trial sequence of trials, you need to call
set
on both beforejump
in thecallback
commandJeremy
Jeremy
KeymasterThe Var element named “practiceRTs” (
which is the one you brought up in your message— EDIT: my bad, the lines of code that refer to that element in your message actually concern another question) keeps track of reaction times, not of accuracy. You need to reset the Var element that keeps track of accuracy tooJeremy
-
This reply was modified 3 years, 4 months ago by
Jeremy. Reason: correction
Jeremy
KeymasterHi Larissa,
The math sounds good to me too: the max duration of timer-D1 is 1600ms, then timer_cue_D2 is 100ms and timer_D3 is 400ms, the max (effective) duration of timer-RT is 1700ms, and you add the 2000ms duration of wait-success, which gives you a max total of 5800ms, so by the time your script reaches
getTimer("wait-separacao").wait()
it will still still have at least 200ms to wait (or more, if timer-D1 was shorter and/or the participant pressed a key before the end of the 1700ms of timer-RT)You need to place
newVar("practiceRTs").global().set( [] ) ,
before beforejump(startsWith("p_trial"))
in thecallback
command, not beforenewButton
, but I forgot to include.global()
in my message above, so mea culpaJeremy
Jeremy
KeymasterHi,
Just create another .js script under Scripts, and start coding there. When the experiment is run, the files in Scripts are concatenated into a single .js file, in an alpha-numeric order, ie. the content of main.js will come after the content of abc.js, so place
PennController.ResetPrefix(null)
at the top of the first script file (or at the top of all script files would work too)It doesn’t matter which file your
Sequence
command is in, it will see all the trials you create from all the .js files in ScriptsJeremy
Jeremy
KeymasterHi,
Use
__counter_value_from_server__
to conditionally execute differentSequence
commands:if (__counter_value_from_server__ % 2) Sequence( "Consent", "block1Instructions", rshuffle("block1"), "block2Instructions", rshuffle("block2"), "block3Instructions", rshuffle("block3"), "block6Instructions", rshuffle("block6"), "block7Instructions", rshuffle("block7"), "block4Instructions", rshuffle("block4"), "block5Instructions", rshuffle("block5"), SendResults() , "Thankyou" ) else Sequence( "Consent", "block1Instructions", rshuffle("block1"), "block2Instructions", rshuffle("block2"), "block3Instructions", rshuffle("block3"), "block4Instructions", rshuffle("block4"), "block5Instructions", rshuffle("block5"), "block6Instructions", rshuffle("block6"), "block7Instructions", rshuffle("block7"), SendResults() , "Thankyou" )
Template
executes its function after the core of the script, so the Var element “blockorder” will not have received its value by the time yourif
is executed. Also,getVar("blockorder")
returns a pointer to the javascript object that represents the Var element, which PennController knows how to interpret, but if you just reference it inside anif
like that, you won’t get what you think (ie. you won’t get"A"
or"B"
). How-to guide: Using JavaScriptJeremy
March 22, 2022 at 1:45 pm in reply to: html layout/event times/selector vs. scale/ compatibility #7951Jeremy
KeymasterHi,
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: referenceThe commands
success
andfailure
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
Jeremy
KeymasterHi Larissa,
This should work:
Template("tabela-target.csv" , row => newTrial("trial_2_center_cue_UP", defaultText .center() .bold() .cssContainer({"position": "absolute", "top": "50%", "left": "50%", "transform": "translate(-50%, +50%)", "font-size": "100px", "margin-top": "1em"}) .print() , newText("D1", "+").color("blue") , newVar("timer-D1-duration").set( 400+Math.round(1200*Math.random() ) ) , newTimer("timer-D1", 1).set( getVar("timer-D1-duration") ).start().wait() , getText("D1").remove() , newText("cue", "*").color("green") , newTimer("timer_cue_D2",100).start().wait() , getText("cue").remove() , newText("D3", "+").color("pink") , newTimer("timer_D3",400).start().wait() , getText("D3").remove() , newVar("newTimerDuration").set( v=>Date.now() ) , newTimer("timer-RT",1700).start() , newText("cruz_central", "+").color("black") , //para cima// newCanvas("center", 500,200) .add( "center at 50%" , "center at 50%" , newImage("imagens", row.imagem).size(500, 200) ) .log() .print("center at 50vw", "top at 85px") , newKey("keypress1","SK") .log("all") .callback( getTimer("timer-RT").stop() ) , getTimer("timer-RT").wait() , getVar("newTimerDuration").set( v=> 3500 - getVar("timer-D1-duration").value - (Date.now()-v) ) , newTimer("wait-separacao", 1).set( getVar("newTimerDuration") ).start() , getKey("keypress1").disable(), getText("cruz_central").remove(), getCanvas("center").remove() , newText("separacao", "+").color("yellow") , getTimer("wait-separacao").wait() ) .log("imagens", row.imagem) .log("item", row.versao) )
Feel free to edit the command on the Canvas element
.print("center at 50vw", "top at 85px")
if the image does not appear where you would like it to appear (I suspect that you want instead is"middle at 50vh"
in place of"top at 85px"
, but it’s your call)I have tested this with one trial twice, and the total duration of the trial was around 4040ms both times
Jeremy
Jeremy
KeymasterThe issue I’m raising in my previous message means one needs to revise the approach if one wants to use the Var method. I can’t spend more time on this today, but feel free to look for an alternative method yourself
Jeremy
Jeremy
Keymaster400+1200=1600, but 400+1600=2000. I was under the impression that you wanted a random duration between 400ms and 1600ms, not between 400ms and 2000ms
Also, I’m just realizing that I reference that variable in a function in
.set
on the Var element, and becausetimerd1duration
is set in aTemplate
environment, by the time the function fromset
is executed it will always have the value it got in the last generated trial, so my code won’t have the desired outcome. More details on the timeline of javascript code injection on this pageJeremy
Jeremy
KeymasterIf you’re referring to the code from this message, it’s not a full code: it’s a streamlined excerpt of your code to which I added the relevant bits to use the Var method
timerd1duration = 400+Math.round(1200*Math.random())
creates a javascript variable namedtimerd1duration
that will store the generated random value (which, in the code from my message, I use when creating the Timer element named timer-D1 and when calculating the duration of the last Timer element). I tookgetText("D1").remove()
directly from your code, it’s your call to keep it or not, depending on what you want to happen at that time in the trialIf you use
newTimer("timer-D1",400+Math.round(1600*Math.random()))
then there’s no point in usingtimerd1duration = 400+Math.round(1200*Math.random())
. You also will get a duration between 400ms and 2000ms (because 400+1600=2000)."timer-D1"
is a string (as you can tell by the double quotes) so you don’t want to include that in an arithmetic operationJeremy
Jeremy
KeymasterAdd
newVar("practiceRTs").set( [] ) ,
beforejump(startsWith("p_trial"))
to reset the Var element, and yes, if you drop/1000
you will have a value in seconds rather than in millisecondsJeremy
Jeremy
KeymasterIt’s hard to tell, one would have to run a few tests using each method and proceed to comparisons, but my guess would be that, under normal circumstances (ie good performance) the delays associated with the Var method probably shouldn’t exceed a couple tens of milliseconds
Jeremy
-
This reply was modified 3 years, 4 months ago by
-
AuthorPosts