Forum Replies Created
-
AuthorPosts
-
Jeremy
KeymasterHi,
Yes, you can use a Key element and its
callback
command to (re)start a Timer element whenever the space bar is pressed, and display the message after that timer has elapsed:newController("DashedSentence", {s: "Hello world, bye Earth"}).print() , newText("reminder", "<em>Press Space to see the next word</em>").center().print() , newTimer("reminder timer",2000) , newKey(" ") .callback( getTimer("reminder timer").stop(), getText("reminder").hidden(), getTimer("reminder timer").start().wait(), getText("reminder").visible() ) , getController("DashedSentence").wait().remove() , getText("reminder").remove() , newButton("Continue") .print() .wait()
Jeremy
November 29, 2021 at 12:43 pm in reply to: html layout/event times/selector vs. scale/ compatibility #7536Jeremy
KeymasterHi,
Is there a way to provide feedback according to the condition of the wrong trial?
Could you pass it in a column? Like
newText("negative feedback", variable_practice.negative_feedback )
. Or you could map a condition column to each message using a Javascript hash:newText("negative feedback", { appropriate: "Wrong answer!", inappropriate: "This sentence is not appropriate because in the picture ABC is depicted", infelicitous: "This sentence is not felicitous because blablabla" }[variable_practice.condition] )
Latin Square: Does the system recognize to load the items belonging to a single group, by simply adding the column “Group” to the template? Should I specify something in the code?
Yes it does: PennController will choose one value out of all the different values listed in the Group column, and only use the rows that contain that selected value in that Group column to generate trials, as explained here
(Should the items belonging to Group 1 be lined up one after the other or is it ok if the table loads line 1 belonging to Group 1, line 2 belonging to Group 2 etc… )
It doesn’t matter how you order your rows. PennController will list the different values in an alphanumeric order, and automatically pick one based on the value of the counter: if you have 3 groups named “A”, “B” and “C” and a participant takes your experiment with a counter value of 5, PennController will only use the rows where the Group column is “C” (because the mapping is {0->A; 1->B; 2->C} and 5 modulo 3 is 2)
Jeremy
Jeremy
KeymasterHi,
The message informs you that your project contains more than 100,000 results lines, and that you will only be served results files up to 100,000 lines. The solution is to download the results in multiple batches, only including series of submissions that total fewer than 100,000 results lines at a time (refresh the page after you download a batch, as sometimes memory gets clogged). Then you can concatenate the multiple CSV files that you’ll have downloaded into a single one on your local machine if you like (on Unix systems, you can do it very quickly with a command like
cat results*.csv > results_all.csv
)I recommend you unpublish your experiment when you do that, to avoid missing new incoming data in the process, and once all your results have securely been downloaded to a safe location, delete them from the farm to free up space in our database, to make saving and accessing future data faster, and to avoid facing this situation again. (Remember to publish the experiment again if you plan on collecting more data)
Jeremy
November 28, 2021 at 6:12 pm in reply to: Comprehension question and rshuffle in self-paced reading #7532Jeremy
KeymasterHi,
1. You could do
newScale("answer", ...[row.Answer1,row.Answer2].sort(v=>0.5-Math.random())
2. You can reuse the exact same code in
Sequence
that you use inseq
. If your question is about labeling your trials so they start by “Target_” or “Filler_” like they do when you manually list them in an array (following the native-Ibex syntax) the answer is simply pass the labels you want as the first argument ofnewTrial
. If your two types of trials are listed in the same CSV table, it’s a good idea to include a column (named Type, for example) that reports the trial’s type, so you can do this:Template("demo_data.csv", row => newTrial( row.Type+"_trial" ,
Jeremy
Jeremy
KeymasterHi,
One option would be to identify the longest text you have and create a Canvas element of a size that would fit it, then print that Canvas element scaled to fit the page. The text will probably appear a little small on some screens, but that’s the only way you can make sure it will fit on a single line. A width of 115em seemed to display fine:
newCanvas("container", "115em", "5em") .scaling("page") .print("center at 50vw","auto") , newController("DashedSentence", {s: row.sentence}) .print( "center at 50%", 0, getCanvas("container") )
Jeremy
November 26, 2021 at 3:13 pm in reply to: html layout/event times/selector vs. scale/ compatibility #7527Jeremy
KeymasterHi,
I have noticed that the calculation of RT within the script is reported in the results, but it’s not correctly reported if I pass the table in R with the tidyverse function.
Do you know what might be the reason?By “the tidyverse” function, do you mean this?
tidied_results <- tidied_results %>% mutate(reaction_time = selection_time - canvas_time, correct = if_else(condition == selection, 1, 0))
This piece of code calculates reaction times post-data-collection, based on the timestamps of each event reported in the results file. In our messages, we had discussed using a Var element to calculate reaction times during runtime and report them as an extra column in every row of the corresponding trial. That solution doesn’t require the table transformation illustrated in the piece of code above
I guess I have to make a column for the expected key each trial of the practice, then after each answer it should check whether the key match or not, if the pressed key is different it should provide the feedback like a text message, and a counter must go up of 1. If the counter at the end of the practice is higher than, let’s say 5, it should reload the trial practice, if it’s below 5, it should load the experimental trial.
This is what I would do indeed. You don’t need to write (non-PennController) javascript code for that, PennController will provide you with what you need
I’ll illustrate with an example here, as I lack information to give a solution adapted to your case, and I actually think doing that would obscure the reasoning anyway. In this example, I want the participant to give more than 2 correct responses before they can proceed:
Sequence( "prepractice", randomize("practice"), "postpractice" ) // (Re)set the Var element to 0 before running the practice session newTrial("prepractice", newVar("practice_score").global().set(0) ) // Very simple trial structure for illustration Template( "table.csv" , row => newTrial( "practice", newText( row.question ).print() , newScale("answer", "Yes", "No") .button() .print() .wait() .test.selected( row.correct ) // Increment if correct answer .success( getVar("practice_score").set(v=>v+1) ) ) ) newTrial("postpractice", // Check the value after the practice session getVar("practice_score").test.is(v=>v>2) .failure( newText("Sorry, you do not meet the threshold").print() , newButton("Take the practice again").print().wait() , // jump will make the experiment go back to "prepractice" after this trial jump("prepractice") ) )
This is the table I used:
question,correct say yes,Yes say no,No don't say yes,No don't say no,Yes
Let me know if you have questions
Jeremy
Jeremy
KeymasterHello,
The documentation page your message links to is outdated. The message at the top of the page invites you to consult the new documentation instead:
You are reading an outdated documentation. Please visit the new documentation instead.
That being said, the piece of code given in the documentation works well. The problem with your script is that you replaced the whole content of main.js with just that piece of code, instead of inserting it inside a
newTrial
that would come afterPennController.ResetPrefix(null)
. I strongly encourage you to read the tutorial to get more familiar with PennController scriptJeremy
Jeremy
KeymasterHello,
This is actually a question that regularly comes back. If you have the same number of words and sentence frames, and you can pair them in any possible ways, you could do something like this. List the sentence frames and the words in the same table:
Sentence,Word Hello _!,world Bye _...,Earth
Then you can do something like this:
words = [] Template( row => newTrial("dummy", words.push(row.Word)) ) Template( row => newTrial( "mytrial", fisherYates(words), word = words.pop() , newButton( row.Sentence.replace('_',word) ).print().wait() ) )
Jeremy
November 17, 2021 at 12:26 pm in reply to: Shuffling blocks while maintaining order in the block #7512Jeremy
KeymasterHi,
I’ll be assuming that your trials are labeled
"block1"
,"block2"
,"block3"
and"block4"
. Then you can do this:PennController.ResetPrefix(null) var blocks = ["block1","block2","block3","block4"]; fisherYates(blocks); Sequence("training", ...blocks)
Jeremy
Jeremy
KeymasterHello,
The database says there are 28 submissions associated with that project, collected via the demonstration link on November 14-15 (only one on the 15th). There is a single submission collected via the data-collection link, from today 11:55UTC
Do you experience the issue for both sets of results?
Jeremy
Jeremy
KeymasterCheck your parentheses:
and
should attach to the Html element’stest
command (as it does in the bit of code that I gave) not to the Button elementJeremy
Jeremy
KeymasterHello,
The expression
$("#alter")
is a jQuery expression, where you can select an element by targeting itsid
attribute in the string simply by prefixing a#
character. Your input element’s id being “sum”, you can get a jQuery object pointing to it using$("#sum")
You can use a Function element to dynamically test the value of that input element in the Button’s
wait
command:newButton("Continue") .print() .wait( getHtml("demographics").test.complete() .failure( getHtml("demographics").warn() ) .and( newFunction(()=>$("#sum").val()) .test.is(100) .failure( newText("must be 100").print() ) ) )
(Note that your original code has
getHtml("consent")
where it should havegetHtml("demographics")
)Jeremy
Jeremy
KeymasterHi,
There is no “twice” option for the Audio element’s
play
command. The “once” option is only there to prevent a secondplay
from looping after it’s been called with “loop” a first timeEven if passing “twice” made the element play twice, the program would have no way of guessing that you want a 3000ms pause between the two playbacks
Why don’t you just do
newAudio("Audio", row.Audio).play().wait() , newTimer(3000).start().wait() , getAudio("Audio").play().wait()
?
Jeremy
Jeremy
KeymasterHi,
I don’t experience any problems or unusual delays when downloading results for my projects. Does the problem persist on your end, and if so, would you mind sharing your project’s demonstration link with me?
Jeremy
Jeremy
KeymasterHello Danny,
Runtime is probably a factor that matters, for the reason you mention (server load). However, browser should not matter when it comes to sending the results to the server (it does matter if, for example, you use the MediaRecorder or EyeTracker elements, which are poorly supported by Safari, if supported at all)
The most important factor regarding data transfer is the amount of data being transferred: if a submission contains thousands of lines, storing them in the server’s database will take time, and as incoming results accumulate, the risk of crash due to overload increases
Jeremy
-
AuthorPosts