Forum Replies Created
-
AuthorPosts
-
Jeremy
KeymasterHi Noe,
Your account was on the exceed-quota list. You’re currently using very little storage space, but maybe you exceeded the 64MB limit before freeing up some space?
Anyway, I took your account off the list, you should be good to go now
Jeremy
Jeremy
KeymasterHi Sam,
You cannot use the
||
operator inside a PennController test command like that. The TextInput text test command accepts either a string or a regex as its argument—what you’re doing here is passing the first non-null disjunct, which will necessarily be new RegExp(variable.Option1) because this constructor will never return null (or undefined, etc).Long story short, you want to build a single regex object that will match both Option1 and Option2, like this: new RegExp(variable.Option1+"|"+variable.Option2)
Jeremy
September 9, 2020 at 10:19 am in reply to: Setting accuracy and RT thresholds for practice block #6057Jeremy
KeymasterHi Agnes,
The partial code you posted will launch the timewindow timer and wait that it has elapsed entirely before proceeding past its wait command, at which point it will reach the LD Key block containing the callback command, which will be ineffective since the timer will have already ended at that point. That’s why the callback that makes it possible to end the timer prematurely must come before the wait command on the timer, as in my code above.
I presume that you declare newVar("RT") before the timewindow timer and set it to Date.now() at that point. Because your getVar("RT") comes after the wait on your timer (and because, as we saw, the Key element cannot end it early) the value of your Var element will be at least as big as row.Time.
The second question, however, should always appear and never be skipped, given the code you posted (unless there is an end command elsewhere).
Here is a code that, I think, will do what you want. It should be embedded in Template of course:
newTrial( "practice" , newVar( "responses" , [] ).global(), newVar("grandaverage", 0).global() .test.is( v => v>=0.5 ).success( end() ) , newText( "fix2" , row.Word ).print() , newKey( "choice" , "FJ" ).log().callback( getTimer("timewindow").stop() ) , newVar("RT").set( v=>Date.now() ) , newTimer( "timewindow" , row.Time ).start().wait() , getKey("choice").disable().test.pressed( row.Correct ) .success( getVar("responses").set(v=>[true,...v]) ) .failure( getVar("responses").set(v=>[false,...v]) ) , getText("fix2").remove() , getVar("RT").set( v=>Date.now()-v ) .test.is( v => v < 2000 ) .failure( newText("Too slow...please respond faster").print() , newTimer(1500).start().wait() , end() ) , newTimer("wait", 500) .start() .wait() , newText("pred","Did you predict the word?").print() , newKey("answer", "ZM") .wait() // This waits for a key press .log("first") )
Note that if row.Time is lower than 2000, then consequently RT will never reach 2000 either (ie. row.Time is the max limit of RT). I chose to print the “Too slow” message for 1.5s before if RT is over 2000, and end the trial immediately after that. If RT is below 2000, the end command is not executed and so the script continues to print the pred Text and wait for a keypress on Z or M before reaching the end of the trial
Let me know if you have questions
Jeremy
Jeremy
KeymasterHi Jesse,
PennController downloads the eyetracking library directly from webgazer’s website, and unfortunately they don’t seem to make newer releases retro-compatible, which is why some scripts that used to work can break with webgazer updates. Anyway, just follow the first note of the documentation page (ie. upload this file to your project) and you should be able to run the experiment through your PCIbex account (the PHP script only matters for sending the data to the server, but the actual task should still go through)
As far as I can tell BlueHost offers the same kind of services as DreamHost, so I don’t see any reason to switch your hosting platform. As long as you know how to upload files (eg. PHP script files) to your webspace and set permissions, which you can do with FTP clients like FileZilla for example, the documentation should get you there. I think you may also need to have a secure domain (ie. https) but other than that the setup should be pretty minimal.
I know of at least one other lab that’s looked into the eyetracker feature, but they haven’t collected actual data with it yet. There’s a Slack channel where people can chat about this, let me know if you’re interested in joining it by sending an email at support@pcibex.net
Jeremy
Jeremy
KeymasterHi Peiyao,
It’s probably an encoding problem. Make sure you save your csv file as UTF-8 and it should display properly.
Jeremy
Jeremy
KeymasterHi,
This worked for me—audio file’s just an example, and I hard-coded ArrowLeft as the correct answer, but you should be able to replace it with row.Correct_answer:
newKey("pressOnArrow", "ArrowLeft", "ArrowRight") .log("all") .callback( getTimer("exposure").stop(), getTimer("timeout").stop() ) , newTimer("exposure", 300).start().wait() , getText("num").remove() , getKey("pressOnArrow").test.pressed() .failure( newTimer("timeout", 5000).start().log().wait() ) , getKey("pressOnArrow") .disable() .test.pressed( "ArrowLeft" ) .success( newAudio("https://upload.wikimedia.org/wikipedia/commons/3/35/Bongo_Agudo.ogg").play().wait() )
Let me know whether that helped fix the problem
Jeremy
September 7, 2020 at 6:20 pm in reply to: Setting accuracy and RT thresholds for practice block #6044Jeremy
KeymasterHi Agnes,
Unfortunately PCIbex does not support loops at the moment, because the sequence of trials is purely linear: it is computed at the very beginning of the experiment based on the Sequence command (if present) and every trial runs one after the other.
A suboptimal alternative would be to repeat the sequence of practice trials multiple times, but only run them fully if the grand average is too low. Something like this:
Sequence( "practice" , "post-practice" , "practice" , "post-practice" , "practice" , "post-practice" , "practice" , "post-practice" , "pre-experiment" , "experiment" ) Template( "practice.csv" , row => newTrial( "practice" , newVar( "responses" , [] ).global(), newVar("grandaverage", 0).global() .test.is( v => v>=0.5 ).success( end() ) , newText( row.Word ).print() , newKey( "choice" , "FJ" ).log().callback( getTimer("timewindow").stop() ) , newTimer( "timewindow" , row.Time ).start().wait() , getKey("choice").disable().test.pressed( row.Correct ) .success( getVar("responses").set(v=>[true,...v]) ) .failure( getVar("responses").set(v=>[false,...v]) ) ) ) newTrial( "post-practice" , newVar("grandaverage") .global() .test.is( v=>v>>0.5 ) .failure( newButton("Next").print().wait() , getVar("grandaverage") .set( getVar("responses") ) .set( v=>v.filter(r=>r==true).length/v.length ) ) , newVar("responses").global().set( [] ) ) newTrial( "pre-experiment" , newButton("Start").print().wait() )
This should run the practice block up to three times, if your participant fails to reach the 50% threshold every time. Otherwise, the test on the grandaverage Var will run the end command at the very beginning of every trial in subsequent blocks, effectively skipping to the experiment trials.
Let me know if you have questions
Jeremy
Jeremy
KeymasterThanks for the clarification. Then this should do what you want:
newText("num", row.Solution) .css("color","white") .css("font-size", "200px") .print() , newKey("pressOnArrow", "ArrowLeft", "ArrowRight") .log("all") .callback( getTimer("exposure").stop(), getTimer("timeout").stop() ) , newTimer("exposure", 300).start().wait() , getText("num").remove() , getKey("pressOnArrow").test.pressed() .failure( newTimer("timeout", 5000).start().log().wait() ) , getKey("pressOnArrow").disable() ) .log( "Correct_answer" , row.Correct_answer ) .log( "ID" , getVar("ID")
Let me know if problems persist
Jeremy
Jeremy
KeymasterHi Peiyao,
What if you try replacing this bit:
e=>getVar("choice").set( e.target.className.replace(/^.*(right|top|bottom|left).*$/,"$1") )._runPromises().then(r)
with this
function(e) { getVar("choice").set( this.className.replace(/^.*(right|top|bottom|left).*$/,"$1") )._runPromises().then(r); }
?
(make sure you don’t lose/add parentheses in the process)
Jeremy
Jeremy
KeymasterHi,
I’m not sure I understand the problem. When I try your code, my first keypress after the 300ms timer has elapsed is captured, regardless of whether (and how many times) I tried pressing a key during those 300ms.
Are you saying you want your results file to report keypresses that happen during the 300ms, but still validate keypresses only after the 300ms? If so, this is one way of doing it:
newText("num", row.Solution) .css("color","white") .css("font-size", "200px") .print() , newKey("pressOnArrow", "ArrowLeft", "ArrowRight").log("all") , newTimer(300).start().wait() , getText("num").remove() , getKey("pressOnArrow").callback( getTimer("timeout").stop() ) , newTimer("timeout", 5000).start().log().wait() , getKey("pressOnArrow").disable() ) .log( "Correct_answer" , row.Correct_answer ) .log( "ID" , getVar("ID")
ie. you create the Key element before the 300ms timer, but only make it stop the timeout timer after those 300ms. You’ll be able to tell whether a key was pressed during the 300ms by comparing pressOnArrow‘s timestamps with timeout‘s timestamp in your results file.
Jeremy
Jeremy
KeymasterHi Peiyao,
The undefined problem comes from your choice Var element not being global and you attempting to access it from outside the parentheses of the corresponding newTrial command. So just make it global when you create it: newVar("choice", 'none').global().log() (don’t forget the pair of parentheses on the log command)
The second problem is a bug in PennController due to the image files being reused across trials. I need to fix it in the next release. In the meantime, just replace
".PennController-left, .PennController-right, .PennController-top, .PennController-bottom"
with".PennController-left-container, .PennController-right-container, .PennController-top-container, .PennController-bottom-container"
and your code should work againLet me know if problems persist
Jeremy
Jeremy
KeymasterHi August,
You cannot really keep track of the post-randomization order in your script (at least not with some advanced coding). However the lines in your results file will appear in the order in which the events and the trials were run. Moreover, comparing the timestamps reported for the trials’ _Start_ events will also tell you in which order they were run.
If you want to add the running order information more directly to your results file, you can add this to your script:
Header( // ... code to be run before every single trial newVar("runningOrder", 0).global().set( v=>v+1 ) ) .log( "runningOrder" , getVar("runningOrder") )
Every line in your results file will then report a number that should increment with each new trial
Let me know if you need more in-depth access to the running order in your script
Jeremy
Jeremy
KeymasterHello,
All the timecodes in the results file are expressed in seconds (10 digits) or milliseconds (13 digits) since January 1 1970 (Unix Time). You can use them in two ways:
1. To determine an absolute time point, for example the time code you reported corresponds to “Mon Aug 31 2020 07:54:24 GMT-0400 (Eastern Daylight Time)” (I got that by typing new Date(1598874864000) in my javascript console)
2. Most usefully, if you subtract the timecodes of two events, you will get how many milliseconds separate them. So if you subtract the timecode for the Start of your trial from the timecode for, say, a click on a button, you’ll know how fast your participant was to click the button
Keep in mind that those timecodes are generated by your participants’ browser as they are completing your experiment, so they won’t necessarily be perfectly accurate when it comes to determining absolute time points (option 1 above) because the internal clock might be off for some participants. However, you’ll always get accurate measures for time differences (option 2)
Jeremy
Jeremy
KeymasterHi Peiyao,
1) As I said, when you click on a button using an external mouse, your cursor will tend to keep moving for a few tens or hundreds milliseconds even after the click. If we didn’t have any timeout, the script would detect such late moves and thus make the cursor visible again almost immediately after hiding it, which would defeat the purpose. Feel free to set it to 500ms (or even lower), I can see how 1s can be too long of a delay
2) Not sure what is happening, it works when I add this after the last call():
, getCanvas("left").remove(),getCanvas("right").remove() , newTooltip("tooltip", "Hello world").print().wait()
Do you happen to have a big transparent Canvas element on which you place your color patches? If you remove the color patches after moving the mouse over them, but don’t remove the big container Canvas, maybe your tooltip is actually placed behind it and clicks don’t make it through—there are multiple solutions, one would be to use .css("pointer-events","none") on the transparent Canvas
Jeremy
Jeremy
KeymasterHi Gabi,
The server indeed appears to be experiencing serious slowdowns, I might need to restart it, which means the farm (and possibly the main website too) will go down for a few minutes, maybe an hour
Apologies for the inconvenience
Jeremy
-
AuthorPosts