PennController for IBEX › Forums › Support › Displaying n words on screen
Tagged: avoid hardcoding
- This topic has 11 replies, 2 voices, and was last updated 1 year, 4 months ago by Jeremy.
-
AuthorPosts
-
May 10, 2023 at 2:44 pm #10557Larissa_CuryParticipant
Hello, everyone! I have to list some lists of words on my screen. I’ve thought of 3 ways of doing it:
Demo link: https://farm.pcibex.net/r/AqPhcF/
a) using images in which every image displays a list, (code below)
b) using images, but making Pcibex get the images from a table (it isn’t working, since it is looping forever) and (code below)
c) I’m wondering if there’s a way to use atemplate
so that I can display as many words as I wish on the screen based on a Table’s interval of rows. For ex, let’s suppose I have “items” (it’s in the demo code below) and I want to display the first 10 rows of the column “myWords”, how do I do that? — I think this would be better!Ps: I have to do this within 1 min and I have to record time (so, time’s up and recording is up after 1 min, participants can go as far as they can within 1 min), so I was doing this before using images (but it would be better to use a table to be able to have more control over the amount of words I’m displaying):
Ps: This is running forever, I don’t know why:
Ps2: I commented the template because it was looping,so it was repeating and not jumping to the next row and moving on
Ps3: I didn’t test it with 1 min yet because I’m still implementing it, that’s why it’s 3000ms// Experimental trial: //Template("items.csv", row => newTrial("experimental-trial", newMediaRecorder("recorder") .record() , newTimer("recording", 3000) .start() // .wait() , newImage("words--A", "wordsA.jpg") .size(800, 500) .cssContainer({ "border-radius": '25px', "border": '2px solid #73AD21'}) .print() , newButton("NEXT", "Next image!") .print() .wait() , getImage("words--A").remove(), getButton("NEXT").remove() , newImage("words--B", "wordsB.jpg") .size(800, 500) .cssContainer({ "border-radius": '25px', "border": '2px solid #73AD21'}) .print() , getTimer("recording") // Refer back to the "timeout" Timer and call the wait command to pause experiment script execution until the Timer stops. .stop() .wait() , newText('a', 'time is up!') , getMediaRecorder("recorder") .stop() .disable() // .print() // .play() , newButton('btn--finish--game', 'Finish Game') .print() .wait() ); //);
May 11, 2023 at 3:00 am #10560JeremyKeymasterHello,
Template
scans the table and produces one output per row. So the idea is, you useTemplate( row => newTrial
to generate one trial per row. Listing one word per row is not the ideal way to go if you want to display several of them at the same time on the page, ie. during the same trialWhat you could do is store one list of words per cell, separated with a character of your choice, say
.
. Here is what it would look like:Template("items.csv", row => newTrial("listOfWords", newMediaRecorder("recorder").log().record() , newTimer("recording", 3000).log().start() // Start the timer now , newText("words", row.words1.split('.').join("<br>")) // separate each word with a <br> tag (new line) .cssContainer({ "border-radius": '25px', border: '2px solid #73AD21', padding: '0.5em' // add some to not get too close to the border }) .print() , newButton("NEXT", "Next words!") .callback( // use a callback to execute this in parallel to waiting for the timer getButton("NEXT").remove() // remove the NEXT button , getText("words").text( row.words2.split('.').join("<br>") ) // update the displayed list of words ) .print() // do not wait for a click, otherwise the timer might elapse before the click , getTimer("recording").wait() // wait for the timer to end , getMediaRecorder("recorder").stop() , getButton("NEXT").remove() // make sure to remove the button, in case the participant didn't get to the second list , getText("words").remove() , newText('a', "Time is up!").print() , newButton('btn--finish--game', 'Finish Game').print().wait() ) )
Example items.csv:
words1,words2 hello.world,bye.earth ibex.is.awesome,pcibex.rocks
Jeremy
May 11, 2023 at 8:46 am #10563Larissa_CuryParticipantHi, @Jeremy! Thank you! But I don’t think it is quite working as I expected. Take a look at the ‘new–itens.csv’ file I’ve uploaded, for ex: https://farm.pcibex.net/r/AqPhcF/
With your code,
a) I’m seeing the words still together by the *.* such as hello.world and bye.earth. I’d need one below the other, such as in a columns (as in the pictures)
b) The timer is restarting after each new list, isn’t it? I need the whole test to be within 1min. For example, in the ‘new–itens.csv’ I have 5 rows of 10 names separated by “_” each, so I’d need 5 columns to be displayed, each with 10 words, one below the other. The participant can go as long as s/he can, but within 1minHow can I fix that avoiding hard coding each collumn myself or uploading pictures?
- This reply was modified 1 year, 5 months ago by Larissa_Cury. Reason: correct my text
- This reply was modified 1 year, 5 months ago by Larissa_Cury. Reason: edit details
- This reply was modified 1 year, 5 months ago by Larissa_Cury.
- This reply was modified 1 year, 5 months ago by Larissa_Cury.
- This reply was modified 1 year, 5 months ago by Larissa_Cury.
May 11, 2023 at 9:18 am #10569Larissa_CuryParticipantPs: I’ve just added a wide version of the data as well, if it’s better this way, called ‘new–Items_Wide’
May 11, 2023 at 9:38 am #10570Larissa_CuryParticipantI fixed letter A, I was using the wrong separator, but I’m still having issues with b)…
I would like to avoid having to hard code every single column name in the wide version or to use only the single column in the long version, because I’ll have many in the real experiment…- This reply was modified 1 year, 5 months ago by Larissa_Cury.
May 11, 2023 at 7:56 pm #10573Larissa_CuryParticipantHi, @Jeremy! [EDIT – UPDATE] I can display the words one below the other and the time seems to be ok (the whole trial is lasting the amount of time and not reseting time), but I’d like to avoid hard-coding this part:
newButton("NEXT", "Next words!") .callback( // use a callback to execute this in parallel to waiting for the timer getButton("NEXT").remove() // remove the NEXT button , getText("words").text( row.Column2.split('_').join("<br>") ) // update the displayed list of words ) .print() // do not wait for a click, otherwise the timer might elapse before the click ,
A) I’d like to be able to have *n* columns as I want displayed dynamically based on the dataframe number of cols in the wide version. Otherwise, I’ll have to hard-code this part *n* times according to the amount of cols of my dataframe.
B) Or, in the long version, I’d like to be able to print as many rows as I want, instead of hard-coding each interval manually.Is there a way to do acheive either a or b? https://farm.pcibex.net/r/AqPhcF/
* Data:
DF: WIDE VERSION: ‘new–Items_Wide.csv”
DF: LONG VERSION: ‘new–items.csv”* Whole code:
Template("new--Items_Wide.csv", row => newTrial("listOfWords", newMediaRecorder("recorder").log().record() , newTimer("recording", 3000).log().start() // Start the timer now , newText("words", row.Column1.split('_').join("<br>")) // separate each word with a <br> tag (new line) .cssContainer({ padding: '0.5em', // add some to not get too close to the border 'text-align': 'center', // trying to make the words center on fullscreen -- NOT WORKING :( 'font-size': '50px', 'position': 'absolute', 'top': '50%', 'bottom': '50%', 'left': '50%', 'width': '100%' }) .print() , newButton("NEXT", "Next words!") .callback( // use a callback to execute this in parallel to waiting for the timer getButton("NEXT").remove() // remove the NEXT button , getText("words").text( row.Column2.split('_').join("<br>") ) // update the displayed list of words ) .print() // do not wait for a click, otherwise the timer might elapse before the click , getTimer("recording").wait() // wait for the timer to end , getMediaRecorder("recorder").stop() , getButton("NEXT").remove() // make sure to remove the button, in case the participant didn't get to the second list , getText("words").remove() , newText('a', "Time is up!").print() , newButton('btn--finish--game', 'Finish Game').print().wait() ) );
- This reply was modified 1 year, 5 months ago by Larissa_Cury.
- This reply was modified 1 year, 5 months ago by Larissa_Cury.
May 12, 2023 at 8:42 pm #10579Larissa_CuryParticipantI’m trying to come up with a way to loop over the table and dynamically set
getText("words").text( row.Column2.split('_').join("<br>") )
so that it displays row.Column{n} as the dataset have, where n is the number of cols in the table and the index of each interation, but I’m really struggling with that, I don’t know if that would be the right way to achieve what I’m trying to achieve above…- This reply was modified 1 year, 5 months ago by Larissa_Cury. Reason: additional comments
May 13, 2023 at 4:41 am #10582JeremyKeymasterHi,
In that case what I would do is list all the words in a single cell (named “Words” for example) and use Var elements to dynamically update the content of the Text element upon pressing the key:
Template("new--Items_Wide.csv", row => newTrial("listOfWords", fullscreen() , newMediaRecorder("recorder", "audio").log().record() , newTimer("recording", 3000).log().start() , newText("words", row.Words.split('_').slice(0,10).join("<br>")) // use slice to get the 10 first words .cssContainer({ padding: '0.5em', 'text-align': 'center', "justify-content": 'center', "align-items": 'center' , 'font-size': '50px', }) .print() , newVar("listOfWords", ""), // we'll set this Var element to the next list of words newVar("nextWordStartsAt").set(10) // this is the index where the next 10 words start , newKey("NEXT", " ") .callback( // first make sure that the index is within bounds getVar("nextWordStartsAt").test.is(v=>v<row.Words.split('_').length).success( // set listOfWords to the next words getVar("listOfWords") .set(getVar("nextWordStartsAt")) // first look up the index .set(v=>row.Words.split('_').slice(v,v+10).join("<br>")) // then use the index+slice to get the next 10 words , getText("words").text( getVar("listOfWords") ) // update the content of the Text element , getVar("nextWordStartsAt").set(v=>v+10) // the next list of 10 words starts 10 words further ) ) , getTimer("recording").wait() , getMediaRecorder("recorder").stop() , getText("words").remove() , newText('time-is-up-msg', "Time is up!").print() , newButton('btn--finish--game', 'Finish Game').print().wait() ) )
Jeremy
May 13, 2023 at 3:28 pm #10586Larissa_CuryParticipantHi, @Jeremy! Thank you very much! Let me ask you something, in case the participant finishes before 60min (which I don’t think will happen, but I have to think about it too, right), can I add a keypress to scape the time?
PS: I’ve made sure that the index is within bounds doing this in R: https://stackoverflow.com/questions/76244042/how-to-insert-strings-so-that-every-row-has-the-same-pattern?noredirect=1#comment134453942_76244042 🙂
Thank you once more! It’s working perfectly!
May 15, 2023 at 6:22 am #10588JeremyKeymasterHi,
Just add
.failure( getTimer("recording").stop() )
to the test on the index for the next 10 words:newKey("NEXT", " ") .callback( getVar("nextWordStartsAt").test.is(v=>v<row.Words.split('_').length).success( getVar("listOfWords") .set(getVar("nextWordStartsAt")) .set(v=>row.Words.split('_').slice(v,v+10).join("<br>")) , getText("words").text( getVar("listOfWords") ) , getVar("nextWordStartsAt").set(v=>v+10) ) // stop the timer if all the words have been exhausted .failure( getTimer("recording").stop() )
Jeremy
May 15, 2023 at 9:09 am #10591Larissa_CuryParticipantHi, @Jeremy! Thank you very much! Could I add a key press too? For example, other than ” ” ? “If you finish before 1min, press K”, for ex? using the same logic with
failure
- This reply was modified 1 year, 4 months ago by Larissa_Cury. Reason: edit question
May 15, 2023 at 9:59 am #10594JeremyKeymasterYou could test the value of the Var element right after you increment it in the
callback
to see if the updated index goes beyond the number of words, and if so, wait for a key press on K to stop the timer:newKey("NEXT", " ") .callback( getVar("nextWordStartsAt").test.is(v=>v<row.Words.split('_').length).success( getVar("listOfWords") .set(getVar("nextWordStartsAt")) .set(v=>row.Words.split('_').slice(v,v+10).join("<br>")) , getText("words").text( getVar("listOfWords") ) , getVar("nextWordStartsAt") .set(v=>v+10) // update the index .test.is(v=>v>=row.Words.split('_').length).success( // if the index is greater than the # of words newKey("K").wait() // wait for a key press on K , getTimer("recording").stop() // stop the timer ) ) )
Jeremy
-
AuthorPosts
- You must be logged in to reply to this topic.