Displaying n words on screen

PennController for IBEX Forums Support Displaying n words on screen

Viewing 12 posts - 1 through 12 (of 12 total)
  • Author
    Posts
  • #10557
    Larissa_Cury
    Participant

    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 a template 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()
      );
    //);
    
    #10560
    Jeremy
    Keymaster

    Hello,

    Template scans the table and produces one output per row. So the idea is, you use Template( 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 trial

    What 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

    #10563
    Larissa_Cury
    Participant

    Hi, @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 1min

    How can I fix that avoiding hard coding each collumn myself or uploading pictures?

    • This reply was modified 11 months, 2 weeks ago by Larissa_Cury. Reason: correct my text
    • This reply was modified 11 months, 2 weeks ago by Larissa_Cury. Reason: edit details
    • This reply was modified 11 months, 2 weeks ago by Larissa_Cury.
    • This reply was modified 11 months, 2 weeks ago by Larissa_Cury.
    • This reply was modified 11 months, 2 weeks ago by Larissa_Cury.
    #10569
    Larissa_Cury
    Participant

    Ps: I’ve just added a wide version of the data as well, if it’s better this way, called ‘new–Items_Wide’

    #10570
    Larissa_Cury
    Participant

    I 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 11 months, 2 weeks ago by Larissa_Cury.
    #10573
    Larissa_Cury
    Participant

    Hi, @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 11 months, 2 weeks ago by Larissa_Cury.
    • This reply was modified 11 months, 2 weeks ago by Larissa_Cury.
    #10579
    Larissa_Cury
    Participant

    I’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 11 months, 2 weeks ago by Larissa_Cury. Reason: additional comments
    #10582
    Jeremy
    Keymaster

    Hi,

    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

    #10586
    Larissa_Cury
    Participant

    Hi, @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!

    #10588
    Jeremy
    Keymaster

    Hi,

    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

    #10591
    Larissa_Cury
    Participant

    Hi, @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 11 months, 2 weeks ago by Larissa_Cury. Reason: edit question
    #10594
    Jeremy
    Keymaster

    You 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

Viewing 12 posts - 1 through 12 (of 12 total)
  • You must be logged in to reply to this topic.