Jeremy

Forum Replies Created

Viewing 15 posts - 91 through 105 (of 1,522 total)
  • Author
    Posts
  • in reply to: Eyetracking R script variations #10670
    Jeremy
    Keymaster

    Hello,

    Unfortunately these questions are rather specific to your project, and much more about transforming data using R than about using PCIbex, so I won’t be answering them here. I suggest you reach out to a peer with good R skills to assist you with your analyses, since once you have loaded your results file in a table, nothing crucially relies on PCIbex and someone familiar enough with R should be able to provide support

    Jeremy

    in reply to: self paced reading experiment #10669
    Jeremy
    Keymaster

    Hello, sorry for the late reply. I see that your project no longer crashes and that you’ve included log commands where necessary. Does this mean you were able to solve your issue?

    Jeremy

    in reply to: Repetitive records BUT different results #10651
    Jeremy
    Keymaster

    The PDF you link to is indeed outdated. Please follow the latest tutorial instead

    As far as I can tell, however, your issue does not come from PCIbex, or from the way you calculate RTs per se. It comes from the fact that some values (fr51, fr24, …) were entered on several occasions, for multiple submissions. As I mentioned in my previous message, and as suggested by the IBEX manual, you could group by MD5+ReceptionTime instead of, or in addition to, ID (which turned out to not uniquely identify submissions, as we found out): group_by(group, Results.reception.time, MD5.hash.of.participant.s.IP.address, ID, entry). But at the end of the day, if you initially assumed that ID should uniquely identify submissions, you should probably try to figure out why that turns out not to be the case

    Jeremy

    in reply to: Repetitive records BUT different results #10646
    Jeremy
    Keymaster

    Hi Chloris,

    The first columns of each line of the results file are described in the IBEX manual: the second column is the MD5 hash, the first one is the reception time of the submission; using the two together reliably identifies the rows that come from the same submission

    The reason why you get the same RT for different scores is that your code calculates RTs across all the scores: group_by(group, ID, entry) groups the data by group, ID and entry, but not by MD5+ReceptionTime, so the groups might contain more than one choice (in case of multiple submissions being associated with the same ID). In those cases where your groups contain several choices, mutate(RT = (mean(EventTime[Parameter=="Choice"] - EventTime[Value=="Start"]))/10) will calculate one RT per group spanning multiple choices. Even though you’re adding a column that contains a single RT value per group, your table at that point still contains multiple choices per group, so when you do filter(Parameter == "Choice")+rename(score = Value) later on, you end up with multiple scores (for those groups that contain multiple ones)

    I don’t know why you got multiple submissions with the same ID: it could be that one participant took the experiment several times, or that they shared their ID with other participants that could have taken the experiment on the same browser+device in some cases. It looks like that didn’t just happen with fr51; you should double-check your results file yourself

    Jeremy

    in reply to: Get the previous row of a column #10645
    Jeremy
    Keymaster

    Hi Larissa,

    A few comments:

    • getVar("errorNum").set(0): this won’t work, because you never create a Var element named “errorNum”
    • newVar("errorCount").set( errorNum + 1): this will always set the value to 1, because you set the javascript variable errorNum to 0 at the top of your script and never update it
    • newText("lastLen", row.lenNumeric).map((w,i) => `${w[i - 1]}`): you are using .map on the closing parenthesis of newText() but there is no command called map on Text elements. It wouldn’t make sense to call .map on row.lenNumeric either, since row.lenNumeric is not an Array (which is the type of object on which the map method is defined)

    I have created a project here to illustrate how to implement the logic you describe (I didn’t include any audio playback or recording). What allows one to share information from one trial to the next is the Var element’s .global command

    Jeremy

    in reply to: How to make keypress add a CSS class to text #10638
    Jeremy
    Keymaster

    Hi Larissa,

    Instead of using .css you could indeed add the rules in the CSS file under .PennController-words { and the result would be equivalent

    The current rule in the CSS file targets .PennController-words .word, that is, elements with the class word that are children of elements with the class .PennController-words. We make sure to add the class word to each span inside the Text element (see the map function) so that selector does target each word individually, as intended

    Jeremy

    in reply to: Picture distortion #10637
    Jeremy
    Keymaster

    Hi,

    The images will be shown at the size you specify in the .size comment. If your original is, say, 1500*850px (a ratio of ~1.8)and you force a size of 450*450px (ratio of 1) then you should expect the image to be displayed distorted. What you can do is .css({"max-width": "450px", "max-height": "450px"}) — if your original image doesn’t have a ratio of 1, its displayed size won’t be 450*450px, but it will be resized so that its longer dimension will be 450px

    Jeremy

    in reply to: Repetitive records BUT different results #10636
    Jeremy
    Keymaster

    Hi Chloris,

    The table you include in your message presents the data after it has been transformed, so unless you provide the script or a detailed explanation of how you obtained that table, I can hardly understand how it maps to the raw results of your experiment

    That being said, judging from your table, it looks like you maybe summarized the data in groups as defined by the ID column above, ie. treated the results as if all the lines referencing “fr51” corresponded to the same submission. That, however, is not the case: I find five submissions in the database that reference “fr51”. Four of those five submissions report the same MD5 hash, indicating that they were taken on the same device using the same browser and the same connection — the remaining submission has a different MD5 hash. I don’t know whether it’s something unexpected for your collection method

    Jeremy

    in reply to: How to make keypress add a CSS class to text #10631
    Jeremy
    Keymaster

    Hi Larissa,

    Part 1: You got it; we embed each word in a span so that the flex display can render them as distinct elements, as otherwise adding them as simple text nodes wouldn’t work

    Part 2: You can read this documentation page to see how PennController elements are rendered in the DOM. cssContainer affects the container element (the one with the .PennController-Text-container class), .css affects the element itself (the one with the .PennController-Text class). The space reserved for each word is the width you set for the .word class

    Part 3:

    1) If you tested for 0, then you would only run the code in callback once when the index is still 0, ie. when pressing space when the first word is highlighted, and then it wouldn’t run again on later key presses, because the value would be greater than 0. The test is just here to make sure that the code in callback won’t be run with an index that would be out of bounds

    3) getVar("listOfWords").set(getVar("highlightedWord")) sets the value of “listOfWords” to the same value as “highlightedWord”, ie. the current index. The next set command uses a function whose parameter represents the current value of the Var element, so we can refer to it in the body of the function: because we just set “listOfWords” to the current index, v in the body of the function refers to the current index, and ${i==v?'highlighted':''} will therefore include the highlighted class only for the word at the current index

    The CSS rule on .word will apply to each individual span inside the Text element’s DOM node; using the .css command on the Text element affects the whole node containing all the span elements, it doesn’t affect each span individually; using the .cssContainer command would be even worse, so to speak, because it would apply yet another level up the DOM hierarchy

    Re. the heights and widths, I refer to the ones where I commented “3 times”: just calculate 4 times instead

    Jeremy

    in reply to: Results Eyetracking Audio results Issue #10628
    Jeremy
    Keymaster

    Would you mind sharing a link to your study, here or at support@pcibex.net so I can take a closer look? If you didn’t run it on the PCIbex Farm or have deleted the results from the platform, would you mind sending a sample of your results file too?

    Jeremy

    in reply to: Results log not complete #10627
    Jeremy
    Keymaster

    Hi,

    Thank you for sharing the link to your study. I have to apologize, I should have paid closer attention to your code. As it turns out, you’re not calling .log on any Audio element, so you cannot expect any line to be added to the results file about playback. The lines you see in the results file report “buffer” events, which are logged anyway to warn you that playback might not have gone through smoothly, but it’s hard to tell what actually happened without the logs of the corresponding “play” and “end” events

    You also misplaced the .log("audio", audio) command on the closing parenthesis of the Button element’s wait command, so you cannot expect the results file to report which audio file corresponds to which item (the fact that you have logs of buffer events that also report the audio filenames are lucky coincidences, in a way)

    I’m not sure why your results file does not contain one line per Scale element, but I note that it’s possible to end the trials without making selections on all the scales. Indeed, you use getScale("selbstbewusstsein","sympathie","erfolg","entspanntheit","intelligenz","vertrautheit","kompetenz","humor","ehrgeiz","freundlichkeit") (and also getTextInput("herkunft","alter","wohnort","situation")) as a way to apply a conjunction of tests on the Scale elements of the names passed as arguments to getScale, but that syntax simply doesn’t exist in PennController. Those will only test one element

    That being said, the results file should still report a line saying “NA” even if a Scale element was never selected. I see that the values in your EvenTime column have been transformed (eg. 1.68485E+12 instead of a full 13-digit integer). Could it be that some lines got lost in the opening/editing process?

    Jeremy

    in reply to: Results Eyetracking Audio results Issue #10624
    Jeremy
    Keymaster

    Hi,

    If the different time positions for the “end” events correspond to different audio files, then it’s no cause for concern

    When a “play” event reports a time position of 0.022991, it means that the event was detected 23ms after the browser had effectively initiated playback, so you can estimate a more accurate timestamp for the beginning of playback by subtracting 22.991 from the EventTime value of the “play” line

    Jeremy

    in reply to: Bidirectional self-paced reading #10623
    Jeremy
    Keymaster

    Hi,

    Since you’ve created a new controller instead of just editing DashedSentence.js, you’ll need to create a file in the Aesthetics folder named BidirectionalDashedSentence.css in which you paste the same rules that already exist in DashedSentence.css

    Jeremy

    in reply to: Results Eyetracking Audio results Issue #10618
    Jeremy
    Keymaster

    Hi,

    1. The values in the EventTime column are timestamps estimating how many milliseconds have elapsed since Jan 1 1970 (UNIX time). What matters is the difference between them: by subtracting the timestamp of one event from that of another, you get how much time separates the two events

    2. You can apply the logic I just mentioned to calculate how much time passed between when the “play” event was logged and when the “end” event was logged, ie. to estimate how long the playback lasted. The values you report are in seconds, they correspond to the in-file position of the player when the events were logged. The value of 0.000485 associated with the “play” event means that the player was at position 0.485ms in the audio file when the event was logged, indicating an infinitesimal delay between when the browser initiated playback and when PennController received the “play” event. For an audio sampled at 48Hz, 0.484ms do not even correspond to a single sample, and it is abysmally shorter than what humans perceive, so you can safely ignore this delay. The 14.069025-13.792653 = 0.276s = 276ms difference, however, is more intriguing. Are these for the same file? What format is it? wav? mp3?

    Jeremy

    in reply to: How to make keypress add a CSS class to text #10614
    Jeremy
    Keymaster

    Hi,

    First let me bring your attention to what I said at the beginning of this message, repeated here:

    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

    If you want to display several words on one screen, listing them on different lines in a CSV file is not the way to go

    One way to implement what you describe is to proceed very similarly to what we discussed in the other thread: instead of incrementing the value of the Var element named “nextWordStartsAt” by 10 on each keypress and replacing the text of the Text element named “words” with the next 10 words, you increment the value by 1 each time and replace the text with the same list of words each time, just edited to place an HTML tag around the next word each time

    So it could look something like this, assuming you always list 9 words in your table’s “Words” column (you could do 12 words as in your example too, just adjust the widths and heights accordingly to fit 4×4 words):

    // embed each word in a span, highlight the very first one
    newText("words", row.Words.split('_').map((w,i)=>`<span class='word ${i==0?'highlighted':''}'>${w}</span>`).join(''))
        .cssContainer("width","810px") // 3 times the space reserved for each word + horizontal padding
        .css({
            display: 'flex',            // items contained in the element will be rearranged smartly
            'flex-direction': 'column', // stack items in columns 
            'flex-wrap': 'wrap',        // items that overflow vertically will start on new columns
            'font-size': '50px',
            height: '210px'             // more than 3 times the space reserved for each word + vertical padding
        })
        .print()
    ,
    newVar("listOfWords", ""), // we'll update this Var element with the list of words tagged as desired
    newVar("highlightedWord").set(0) // this is the index of the highlighted word
    ,
    newKey("NEXT", " ")
        .callback(
            // first make sure that the next index is within bounds
            getVar("highlightedWord").test.is(v=>v+1<row.Words.split('_').length).success(
                getVar("highlightedWord").set(v=>v+1) // increment the index of the highlighted word
                ,
                getVar("listOfWords") // update listOfWords with appropriate tags
                    .set(getVar("highlightedWord")) // first look up the index
                    .set(v=>row.Words.split('_').map((w,i)=>`<span class='word ${i==v?'highlighted':''}'>${w}</span>`).join('')) // now set the class as desired
                ,
                getText("words").text( getVar("listOfWords") ) // update the content of the Text element
            )
        )

    In global_main.css, you add these rule:

    .PennController-words .word {
        width: 230px;
        height: 60px;
        padding: 5px 15px;
    }
    .PennController-words .word.highlighted {
        outline: solid 10px yellow;
        border-radius: 0.25em;
    }
    

    Just make sure the width you pass in your script to .cssContainer is at least 3 times (the width + 2*padding) and the height you pass to .css is at least 3 times (the height + 2*padding), that you set in the file’s CSS rule for .word.

    Jeremy

Viewing 15 posts - 91 through 105 (of 1,522 total)