Forum Replies Created
-
AuthorPosts
-
JeremyKeymasterHi,
1. The analysis part is up to you. If you discard the (0,0) data points to focus on (0,1) vs (1,0), you’ll be looking at left-vs-right preference when the participant is (estimated to be) looking at either left or right; but keep in mind that it could be that the participant is not looking at either the left or right image for some time. For example, you could get a 30% left vs 70% right distribution when discarding the (0,0) data points, but only (15% left vs 35% right) vs 50% neither when factoring in all the data points
2. Subtract the EventTime value of the tracker element from the EventTime value of the audio element from your results file: you’ll get the offset for when the audio started relative to when the tracker started. Then add 697 to that number, and you’ll get the offset relative to the tracker’s start time for the word onset. Then you can compare that number to the
timevalues from the eye-tracker data file and, for example, discard all the lines wheretimeis lower than that number3. It is not possible to add a column to the eye-tracking data file during runtime. However you can use the
trialcolumn from that file to cross-reference the PennController trial ID from the results file, and add an “itemNo” column during analysis if you wantJeremy
JeremyKeymasterHi Larissa,
If you end the trial immediately after a selection is made, there just won’t be enough time to hear the audio which starts playing but is stopped immediately, along with the trial’s end. Using
waiton the Audio element, as in your last message, after thewaiton the Selector element has been released, is one solution to make sure that the trial doesn’t end before the audio is done playingJeremy
JeremyKeymasterIt won’t make a difference, since the
waitcommand will be released as soon asgetTimer("timeout").stop()from thecallbackcommand has been executed; the commandgetAudio('keyPressAudio').play()insidecallbackwill just run in parallel togetImage('stimuli').remove()and the commands coming after that (including thesetcommands further down) from the main threadJeremy
JeremyKeymasterYou want to replace
getKey("answerKey").disable().test.pressed("K", "S")withgetKey("answerKey").disable().test.pressed(): this line is in afailurecommand which already corresponds to a situation where the correct key wasn’t pressed so if, in that situation,test.pressed()succeeds it means that the incorrect key was pressed, and if it fails it means that no key was pressedOther than that I don’t see any problems with this piece of code
Jeremy
JeremyKeymasterHi,
callbackcommands inform the script of what to do whenever the relevant event happens, and immediately move on to the next line in the script. By contrast,waitcommands halt the execution of the script until the relevant event happens, after which only do they move on to the next line in the script. When you have these lines in a script:newTimer("timeout", 5000).start() // A , newVar("RT").global().set( v => Date.now() ) // B , newKey("answerKey","SK").log("all").callback( getTimer("timeout").stop() ) // C , getTimer("timeout").wait() // D , getVar("RT").set( v => Date.now() - v ) // EThe script first executes (A): it starts a 5s timer and moves on to (B) without waiting for the timer to elapse (because there is no
waitcommand in A). At (B), which is executed immediately after (A), the scripts sets the Var element to the current timestamp, ie. a timestamp that corresponds to when the timer was started. The script immediately moves on to (C), which evaluates thecallbackcommand: here, the script learns that whenever the participant presses S or K, the commandgetTimer("timeout").stop()should take effect. But importantly, there is nowaitcommand in (C) so the script immediately moves on to (D), but it now keeps in mind what should happen were the participant to press S or K at any point. At (D) the script sees awaitcommand so it stays on (D) until the timer has stopped. This could happen because the 5s have elapsed, the normal course of events for a timer; or it could happen because the timer was stopped early, which is precisely what we instructed the script to do if the participant ever presses S or K, in the precedingcallbackcommand. So when the timer stops, regardless of which scenario we’re in, the script then moves on to (E) and sets the Var element to the current timestamp minus the previous one. If we’re in a scenario where the participant didn’t press S or K, then the script must have reached this line after waiting 5s, so the subtraction will result in that duration. But if we’re in a scenario where the timer was stopped because the user pressed S or K, then it hasn’t been 5s yet, and the subtraction will reflect that, and the result of the subtraction will be a lesser value. Once the Var element has been set, the script immediately moves on to the next line (if any)Jeremy
August 2, 2023 at 2:30 am in reply to: Question about assigning conditions, groups + randomization #10796
JeremyKeymasterHi,
As per the IBEX documentation,
rshufflewill evenly distribute the trials as identified by the labels you pass to the function. If you label your filler trials differently from the other ones, and one argument ofrshufflecaptures those labels, then it will try to separate any two filler trials by the same number of other trials. Using that method, as long as you don’t have 6 times as many filler trials as other trials, you shouldn’t end up with 6 fillers in a rowIf you don’t want the sort of even distribution you get from
rshuffle, thenrandomizeNoMoreThanis the way to go. Just make sure you have proper references to your trials’ labelsJeremy
JeremyKeymasterHi,
The MediaRecorder element does not place any constraints over transfer, it is the browser that requires CORS validation when sending a POST request from one domain (farm.pcibex.net) to a different domain (where your server is hosted). It could be that you somehow overrode the certificate’s invalidity in your instance of Firefox, but other browsers will just refuse to proceed with the POST request in the absence of a valid certificate
It is possible to use a self-signed certificate, but you’ll likely run into issues like the one you describe here. If possible, I recommend using certbot to automatically get letsencrypt certificates, which won’t necessitate manual approval
Jeremy
July 24, 2023 at 10:27 am in reply to: Question about assigning conditions, groups + randomization #10789
JeremyKeymasterHi,
You don’t have to make them uniform, but one thing you can do is check for the presence of columns before logging them, eg:
.log("adjectivenumber", "adjectivenumber" in row ? row.adjectivenumber : "") .log("adjectiveclass", "adjectiveclass" in row ? row.adjectiveclass : "") .log("pair", "pair" in row ? row.pair : "") .log("context_adjective", "context_adjective" in row ? row.context_adjective : "") .log("target_adjective", "target_adjective" in row ? row.target_adjective : "") .log("target_polarity", "target_polarity" in row ? row.target_polarity : "") .log("contextcomparative", "contextcomparative" in row ? row.contextcomparative : "") .log("comparativequestion", "comparativequestion" in row ? row.comparativequestion : "") .log("contextequative", "contextequative" in row ? row.contextequative : "") .log("equativequestion", "equativequestion" in row ? row.equativequestion : "") .log("questionquestion", "questionquestion" in row ? row.questionquestion : "")Jeremy
JeremyKeymasterHi,
You cannot reference a Var element in a
newXcommand, because elements are created upon opening the experiment but evaluated upon runtimeThe solution is to use the
.textcommand:newTrial('test', newVar('var-int','hello') , newText('text') .text( getVar('var-int') ) .print() , newButton('button','Click') .print() .wait() )Jeremy
JeremyKeymasterThis issue was reported as resolved in a private email exchange, through the use of the
callbackcommandJeremy
JeremyKeymasterHi,
You are not supposed to call
starton an EyeTracker element that’s already started. When.logis called on the EyeTracker element, lines are added to the results file, including one line that tells you when.startwas executed and reporting the corresponding timestamp. Then you can use thetimescolumn from the .csv output file to calculate when each gaze estimate was recorded (EventTime+times). For example, the value of 0 in your sample simply corresponds to the tracker’sstarttimestamp (not sure which of the twostarts though, but you can determine that using the timestamps ofprinton the Left and Right Canvas elements, since you print those between the tracker’s first and secondstarts). Comparing those values with the timestamps reported in your results file for other events, such as audio start/stop, will give you an idea of where the participant was looking during the unfolding of the event in the trialJeremy
JeremyKeymasterThis issue was addressed in a private email exchange
Jeremy
JeremyKeymasterHi,
My bad, I read your message too fast. There’s no problem with changing the message in PennController.js
Jeremy
JeremyKeymasterJuly 20, 2023 at 3:40 am in reply to: Question about assigning conditions, groups + randomization #10767
JeremyKeymasterHi Kate,
Your
Sequencecontainsrshuffle("experiment", startsWith("experiment"))and both your target and filler/MP trials have labels that start with “experiment” (it actually is the whole label for the latter) so the latter are included twice. UsestartsWith("experiment_")insteadThe stack of
.logcommands starting with.log("adjectivenumber", row.adjectivenumber)are attached to the preceding.wait()command relative to the Scale element. You want to attach it to the closing parenthesis ofnewTrial()instead (the one before the comma you placed aboveSequence)Jeremy
-
AuthorPosts