Forum Replies Created
-
AuthorPosts
-
Jeremy
KeymasterHi,
Would you mind sharing the link to your experiment with me, either here or privately at support@pcibex.net? The end command only stops the current trial, so if it runs through the end of your experiment, it may be coming from an interaction with your specific design
Oh and I forgot to address the “pause” component from your first message. One option is to add a Header that will pause execution if a Var element has been set to true when clicking the button, eg:
Header( newVar("pause", false).global().test.is(true).success( newButton("Resume").print().wait().remove(), getVar("pause").set(false) ) )
Of course you also want to add getVar("pause").set(true) before end in the callback of your pause button
Jeremy
November 30, 2020 at 12:40 pm in reply to: Trying to set a unique participant ID/code for Amazon Mechanical Turk payment #6407Jeremy
KeymasterGlad you found a solution!
For reference, b64_md5 is a function defined as part of Ibex, it is not a standard javascript function. It expects a string passed as its argument (Date.now() + Math.random() is a number, which is why it needs to be converted into a string with .toString()) and outputs an encoded string uniquely corresponding to the input string
Jeremy
Jeremy
KeymasterHi Aliona,
One option would be to use the pick function defined in this thread:
critical = randomize("critical_trials") fillers = randomize("fillers") Sequence( rshuffle(pick(critical,7),pick(fillers,10)),"break", rshuffle(pick(critical,7),pick(fillers,10)),"break", rshuffle(pick(critical,6),pick(fillers,10)) )
Let me know if you have questions
Jeremy
Jeremy
KeymasterHi Rosa,
I am not able to reproduce your keypress problem: the experiment does proceed to the next trial as soon as I press the spacebar when I see the “Press SPACEBAR” message, regardless of whether or which key I pressed during the 2000ms. Do you have another Key element named “spacebar” in your trial by any chance, or any other conflicting Key element in a Header or a Footer? You could also try disabling Key elements after you’re done with them, e.g. add getKey("response").disable() before your “spacebar” Key element (but again, I can’t identify your problem so it’s just a wild guess)
Regarding the conditional feedback messages, you can do something like this:
getKey("response") .test.pressed() .success( getKey("response").test.pressed(row.answer) .failure(newText("negative feedback", "Wrong answer!") .log() .print() .center() .cssContainer({"font-size": "160%", "color": "red"}) ) ) .failure(newText("slow", "Too slow...") .log() .print() .center() .cssContainer({"font-size": "160%", "color": "red"}) )
Let me know if you have questions
Jeremy
Jeremy
KeymasterHi August,
Apparently there is a max-width CSS property that’s being set to content in some versions of PennController, which limits the maximum size you can pass. Just add .css("max-width", "unset") after your size command and that should do the trick
As for the color, the default rendering of the slider is handled different by each browser. If you want to modify its aesthetics, you’ll have to do some CSS magic
Jeremy
Jeremy
KeymasterSorry, my explanations of the timeline weren’t clear, so I will walk through them in more detail.
The first lines, the ones with “0ms” on the left, correspond to the execution of the lines from your script starting with newImage("fixationpoint", row.Fixation), which is executed immediately after the end of your Header, up to newTimer(700).start().wait(): all of them are executed so quickly that they virtually take no time, which is why I associated them all to the 0ms time point.
After the two wait commands on your first (unnamed) Timer elements have finished running, the script reaches the line getImage("fixationpoint"): that’s where the timeline reaches the time point “1850ms.” All the lines from that one up to newTimer("exposure", 300).start().wait() are executed in the blink of an eye, including the callback command of your Key element. Crucially, that command has an effect lasting for most of the rest of the timeline: from that time point on, whenever the participant presses the left or the right arrow, both the “exposure” and the “timeout” Timer elements will be stopped (if they were running during the keypress, that is).
After that time point, the timeline is no longer purely deterministic, because the course of events will depend on whether the participant does or doesn’t press a key during the execution of the Timer elements. Starting at time point 1850ms, the “exposure” Timer element starts and will run for 300ms unless the participant presses the left-arrow or right-arrow key. If the participant does not press a key, then the “exposure” Timer element elapses entirely and you are 2150ms in the trial. If the participant does press one the two arrows before that, the “exposure” Timer element is stopped prematurely and you are anywhere between 1850ms and (strictly before) 2150ms.
In either case, the “exposure” Timer element has stopped (either because it elapsed fully, or because it was ended prematurely) and the script reaches line getKey("pressOnArrow").test.pressed() and the corresponding failure command. That failure command will take effect only if the participant has not pressed one of the two arrows until then. Now remember, at this point, there are two possibilities: either the timer was ended prematurely by a keypress on one of the two arrows and the time point is not 2150ms yet, or the “exposure” Timer element has elapsed fully because no key was pressed and it has been 2150ms. Only in the latter case will the failure command take effect, and will the “timeout” Timer element start running and logging. If the participant did press a key (and it hasn’t even been 2150ms), then the “timeout” Timer element will not run and will not report any line to the results file.
This means that if your results file does report lines for the “timeout” Timer element for an item, your participant has not pressed one of the two arrow keys during the 300ms “exposure” Timer element: any relevant keypress therefore happened more than 2150ms after the end of the Header. However, if you see no such lines for an item, it means that the participant did press one of the two arrow keys before the 300ms of the “exposure” Timer element elapsed entirely, and therefore the keypress happened before 2150ms-after-the-end-of-Header. Item 60 corresponds to the first case: subtracting the time event for the keypress from the time event for the end of the Header gives 3956ms, which is well past the 2150ms signaling the end of the (uninterrupted) “exposure” Timer element. Item 68, on the other hand, corresponds to the second case: the same subtraction gives 2044ms, which is before the “exposure” Timer element has had time to fully elapse, and so the failure command did not take effect and the “timeout” Timer element was not run at all for item 68.
I hope the timecourse of events of your trials is clearer now. As I said, if you’re planning to re-run this, you could add a log command to your “exposure” Timer element so you get lines added to your results file reporting when that Timer element started (it should always be around 1850ms) and when it ended (anywhere between 1850ms and 2150ms).
Let me know if you have any questions
Jeremy
Jeremy
KeymasterHi,
It depends on how you implemented those multiple choice questions.
You can see the general structure of any PennController element printed on the page here. You can also open your browser’s inspector to get a finer look at how the different elements are structured on the page and, most importantly, their CSS classes, and write rules accordingly in a file named global_z.css
Or you can directly use the css and/or cssContainer commands on your elements, if it makes sense with the particular way you implemented your multiple choice questions
Jeremy
Jeremy
KeymasterHi,
This doesn’t happen at random, it’s just consistent with your script: you only start and log the “timeout” Timer element if no key was pressed during the exposure period, otherwise you just never even deal with that Timer element, so it won’t appear in your results files. Here’s a step-by-step reading of your script (the “any time”s correspond to whether the participant pressed a key that would stop the timers prematurely):
0ms print "fixationpoint" ; print "primero" start playing "primero" ; start 700ms timer and wait [ ... ] 700ms start playing "segundo" ; start 1150ms timer and wait [ ... ] 1850ms remove "fixationpoint" ; print "num" listen to keypresses on left/right arrow (will be logged) associate keypresses with [ stop "exposure" ; stop "timeout" ] start 300ms "exposure" timer and wait [ ... ] any time remove "num" btw 1850 **if NO key was pressed (2150ms)**: & 2150ms [ start 5000ms "timeout" timer (will be logged) and wait ] any time stop listening to keypresses btw 1850 **if correct key was pressed*: & 7150ms [ play "coin7" and wait ] any time end of current trial btw 1850 move to next trial & 7150 + audio ms
Consistently, you’ll find that for item 60, 3956ms elapsed between the reported keypress and the end of your Header, which necessarily means that no key was pressed during the exposure timer (which takes place between 1850 and 2150ms). For item 68, however, the keypress happened 2044ms after the end of your Header, which means approximately 100ms before the end of the “exposure” timer (or, 200ms after it started). So the failure command on the Key was just not validated (ie. a key had been pressed indeed at that point) and the “timeout” timer was just never started nor told to be logged. So there’s not really any data to recover here, because the “data” doesn’t correspond to anything that actually happened.
Don’t you get the desired reaction time by subtracting the Header-end time event from the keypress time event though, the way I just did?
You could also add log onto your “exposure” Timer element, which will add a line reporting when it started (and ended), so you can subtract the start time event from the keypress. It would probably more accurately reflect the reaction time you’re after, as I understand your design
Jeremy
Jeremy
KeymasterHi Susanne,
Sorry, I hadn’t understood your question. You are correct, it’s not possible to re-loop through training.csv using PCIbex at the moment.
Let me know if you have more questions
Jeremy
Jeremy
KeymasterHi Susanne,
You can increment a Var element upon success, check the value of that Var element at the beginning of your trials and only run them if it’s below 2. No need to resort to plain javascript:
Template("training.csv", row => newTrial("training", newVar("training_successes", 0) .global() .test.is( v => v > 2 ) .success( end() ) , newController("Maze", {s: row.Sentence, a: row.Distractor}) .css("font-size", "1.5em") .css("font-family", "Verdana") .print() .log() .wait() .remove() .test.passed() .failure( newText("<br/>oops!").css("font-size", "1.5em").css("color", "red").print() ) .success( getVar("training_successes").set( v => v+1 ), newText("<br/>great!").css("font-size", "1.5em").css("color", "green").print() ) , newTimer(500).start().wait() ) )
Let me know if you have questions
Jeremy
Jeremy
KeymasterHi Nicoletta,
You cannot control the mouse cursor for security reasons, but what you can do is print a button at the center of the screen that needs to be clicked before proceeding:
newButton("Go").print("center at 50vw", "middle at 50vh").wait().remove()
Cross-referencing this topic: Centering mouse cursor at the start of the trial
Jeremy
Jeremy
KeymasterHi Yana,
I think you’re doing the right thing inserting your code in the wordPauseTimeout function, but when I open the js file I see that line 152 is part of the wordTimeout function, so I just want to make sure you’re editing the right function.
However I’m afraid that directly modifying t.wordTime will cause problems after encountering the first over-12-character word, because the subsequent words will inherit the extra duration. Here is how I rewrote the whole if statement, and it seems to be working smoothly:
if (this.mode == "speeded acceptability") { var t = this; function wordTimeout() { t.blankWord(t.currentWord); ++(t.currentWord); if (t.currentWord >= t.stoppingPoint) t.finishedCallback([[["Sentence (or sentence MD5)", t.sentenceDesc]]]); else t.utils.setTimeout(wordPauseTimeout, t.wordPauseTime); } function wordPauseTimeout() { t.showWord(t.currentWord); t.utils.clearTimeout(wordPauseTimeout); let duration = t.wordTime; if (t.words[t.currentWord].length > 12) { var extraTime = (t.words[t.currentWord].length - 12) * 200; duration += extraTime; } t.utils.setTimeout(wordTimeout, duration); } wordPauseTimeout(); }
I used 200 so I could clearly tell when the extra time was added to the normal display time. For reference, here are the parameters I used to test the DashedSentence:
{ s: "Extralongitudinal is not a word that makes much anticonstitutional sense", wordTime: 250, mode: "speeded acceptability" }
Jeremy
Jeremy
KeymasterOh, right, my bad, that makes perfect sense actually, because the aesthetics changes along with the message by default. You’ll have to use the second, runtime method described above then
Jeremy
Jeremy
KeymasterHi Nikhil,
“Finish the trial” can mean vastly different things depending on your task and your desiderata. You’ll need to make decisions as to what, precisely, should happen with each element in your task when the button is clicked. A very radical and easy-to-implement option is to just drop everything altogether, all you need to do is print a button whose callback will call end:
newButton("Stop").callback( end() ).print()
You can use as many commands as you want in the callback, so if you need to do anything with your existing elements (eg. stop some audio playback) before ending the trial, just do it there too
Let me know if you have questions as you implement your own solution
Jeremy
Jeremy
KeymasterHi,
If you can live with the message having the same background color whether it says “Not recording” or “Recording…”, all you need to do is upload a file named global_z.css with the following:
#bod table + div:last-child { background-color: lightblue !important; }
If you want to use different custom colors for the two states, you’ll need to use the method from the message above:
newTrial( newButton("Go fullscreen").print().wait().remove() , fullscreen() , newMediaRecorder("video").print().log().record() , newFunction(()=>$("div:contains(Recording...)").css('background-color','lightblue')).call() , newTimer(60000).start().wait() // Record for 1min , newFunction(()=>$("div:contains(Recording...)").css('background-color','lightgray')).call() , getMediaRecorder("video").stop() , newButton("Next").print().wait() )
Let me know if you still have questions
Jeremy
-
AuthorPosts