Forum Replies Created
- 
		AuthorPosts
- 
		
			
				
March 28, 2022 at 9:29 am in reply to: html layout/event times/selector vs. scale/ compatibility #7978 JeremyKeymaster JeremyKeymasterHi, The code of the blankfunction 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  JeremyKeymaster JeremyKeymasterHi Larissa, One issue is that you have at least one case where the logcommand 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 Keyas its parameter instead ofPressedKey,NAas its value andNeverin 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 NAs 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  JeremyKeymaster JeremyKeymasterHi Sharon, Just refer to the column of your table in the testcommand: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  JeremyKeymaster JeremyKeymasterYes: 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 seton both beforejumpin thecallbackcommandJeremy  JeremyKeymaster JeremyKeymasterThe 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, 7 months ago by  Jeremy. Reason: correction Jeremy. Reason: correction
  JeremyKeymaster JeremyKeymasterHi 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 thecallbackcommand, not beforenewButton, but I forgot to include.global()in my message above, so mea culpaJeremy  JeremyKeymaster JeremyKeymasterHi, 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 Sequencecommand is in, it will see all the trials you create from all the .js files in ScriptsJeremy  JeremyKeymaster JeremyKeymasterHi, Use __counter_value_from_server__to conditionally execute differentSequencecommands: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" )Templateexecutes its function after the core of the script, so the Var element “blockorder” will not have received its value by the time yourifis 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 aniflike 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 #7951 JeremyKeymaster JeremyKeymasterHi, I’m not sure I’m following everything, but anddoes not mean “and do something else,” it is used to write a conjunctive test: referenceThe commands successandfailureaccept 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 testcommands 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  JeremyKeymaster JeremyKeymasterHi 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  JeremyKeymaster JeremyKeymasterThe 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  JeremyKeymaster JeremyKeymaster400+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 .seton the Var element, and becausetimerd1durationis set in aTemplateenvironment, by the time the function fromsetis 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  JeremyKeymaster JeremyKeymasterIf 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 namedtimerd1durationthat 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  JeremyKeymaster JeremyKeymasterAdd newVar("practiceRTs").set( [] ) ,beforejump(startsWith("p_trial"))to reset the Var element, and yes, if you drop/1000you will have a value in seconds rather than in millisecondsJeremy  JeremyKeymaster JeremyKeymasterIt’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, 7 months ago by 
- 
		AuthorPosts