Jeremy

Forum Replies Created

Viewing 15 posts - 1,051 through 1,065 (of 1,522 total)
  • Author
    Posts
  • in reply to: log global vs. local variable #6318
    Jeremy
    Keymaster

    Hello,

    You have a problem with the parentheses of your first trial: all your newVar blocks are inside the wait command of the Button, and all your .log(...,getVar(...)) are attached to the closing bracket of that wait command, when they should be attached to the closing parenthesis of newTrial:

    newTrial( "Angaben" , 
        newText("Ueberschrift", "<h2>Stichproben-relevante Angaben</h2>").center().print()
        ,
        newTextInput("inputAlter").size("100px")
        ,
        newScale("inputGeschlecht", "männlich", "weiblich", "divers")
        ,
        newScale("inputHaendigkeit", "linkshändig", "rechtshändig")
        ,
        newTextInput("inputGeboren")
        ,
        newTextInput("inputWohnsitz")
        ,
        newScale("inputDeutsch", "ja", "nein")
        ,
        newTextInput("inputMuttersprache")
        ,
        newTextInput("inputProlific-ID")
        ,
        newCanvas("Canvas", 600, 320)
            .add( 0,     0, newText("Alter:"))
            .add( 400,   0, getTextInput("inputAlter").log())
            .add( 0,    40, newText("Geschlecht:"))
            .add( 400,  40, getScale("inputGeschlecht").log())
            .add( 0,    80, newText("Händigkeit"))
            .add( 400,  80, getScale("inputHaendigkeit").log())
            .add( 0,   120, newText("Geboren in (Bundesland/Staat):"))
            .add( 400, 120, getTextInput("inputGeboren").log())
            .add( 0,   160, newText("Derzeitiger Wohnsitz (Bundesland/Staat):"))
            .add( 400, 160, getTextInput("inputWohnsitz").log())
            .add( 0,   200, newText("Deutsch als Muttersprache?"))
            .add( 400, 200, getScale("inputDeutsch").log())
            .add( 0,   240, newText("Muttersprachen (außer Deutsch):"))
            .add( 400, 240, getTextInput("inputMuttersprache").log())
            .add( 0,   280, newText("Prolific-ID:"))
            .add( 400, 280, getTextInput("inputProlific-ID").log())
            .print()
        ,
        newText("Warnung1", "Bitte füllen Sie die Pflichtangaben aus.")
            .color("red")
            .italic()
            .center()
            .hidden()
            .print()
        ,
        newButton("Weiter") 
            .center()
            .print()
            .wait( getTextInput("inputAlter").test.text(/.+/)
                .and(getTextInput("inputGeboren").test.text(/.+/))
                .and(getTextInput("inputWohnsitz").test.text(/.+/))
                .and(getTextInput("inputProlific-ID").test.text(/.+/))
                .and(getScale("inputGeschlecht").test.selected())
                .and(getScale("inputHaendigkeit").test.selected())
                .and(getScale("inputDeutsch").test.selected())
                .failure( 
                    getText("Warnung1").hidden()
                    ,
                    newTimer(100).start().wait()
                    ,
                    getText("Warnung1").visible() 
                )
            )
        ,
        newVar("Alter").global().set( getTextInput("inputAlter") )
        ,
        newVar("Geboren").global().set( getTextInput("inputGeboren") )
        ,
        newVar("Wohnsitz").global().set( getTextInput("inputWohnsitz") )
        ,
        newVar("Muttersprache").global().set( getTextInput("inputMuttersprache") )
        ,
        newVar("Prolific-ID").global().set( getTextInput("inputProlific-ID") )
            ,
        newVar("Geschlecht").global().set( getScale("inputGeschlecht") )
        ,
        newVar("Haendigkeit").global().set( getScale("inputHaendigkeit") )
        ,
        newVar("Deutsch").global().set( getScale("inputDeutsch") )
    )
    .log("Alter", getVar("Alter"))
    .log("Geschlecht", getVar("Geschlecht"))
    .log("Haendigkeit", getVar("Haendigkeit"))
    .log("Geboren", getVar("Geboren"))
    .log("Wohnsitz", getVar("Wohnsitz"))
    .log("Deutsch", getVar("Deutsch"))
    .log("Muttersprache", getVar("Muttersprache"))
    .log("Prolific-ID", getVar("Prolific-ID"))
    .setOption("countsForProgressBar", false)
    .setOption("hideProgressBar", true)

    Jeremy

    in reply to: Editing the link in InitiateRecorder() #6315
    Jeremy
    Keymaster

    Hi,

    Your code works just fine when I test it. I’m using the most recent version of PennController (1.8) in which VoiceRecorder is deprecated in favor of MediaRecorder, but your code is still retro-compatible.

    The only problem I have is that the “Record” button should be reading “Stop” instead, because you start recording before printing the interface. The continue button only appears after I click “Record” (which, again, should read “Stop”) and if I click the continue button, then it proceeds to the next trial, because I’m done recording: I clicked Stop, even though it misleadingly read “Record.”

    Here’s what you can do to fix the text of the “Record/Stop” button:

    newVoiceRecorder("recorder") 
        .log()
        .print()
        .record()
    ,
    newFunction( 
        ()=>$(".PennController-MediaRecorder-record").html("Stop") 
    ).call()
    ,
    getVoiceRecorder("recorder").wait()

    Let me know if you have questions

    Jeremy

    in reply to: Specifying file names for recorded audios #6314
    Jeremy
    Keymaster

    Hello,

    With the most recent versions of PennController, the media files are named after the element’s name, so if you have newMediaRecorder( "production", "audio" ) then the filename will be production.webm (assuming your browser saves the audio file as webm, and you have no other MediaRecorder element named production in the course of your experiment).

    The uploaded zip files containing the audio files, however, are named using (almost perfectly) unique strings, to avoid upload conflict issues, and also because the various audio files from the same trial or even from multiple trials can all end up packaged in a single zip file in a non-deterministic way

    Jeremy

    in reply to: reaction time results appear in different two columns #6311
    Jeremy
    Keymaster

    Hi,

    -I moved (whichtense) also for the fillers MC following the same codes and it works fine. but they still have NA for the three columns CQcorrect, RQcorrect, MCcorrect although I set that in my pcibex script.

    If you did not generate your filler items using a Template but still used something like .log( "CQcorrect" , row.CQcorrect ) on your filler trial, then you got NAs because there is simply no row for row to point to

    -I also moved choose(for nationality) and choose2 (for English level) and that worked in the correct_which_results but appear with NA in the main tmp ! I do not really know why!

    Your choose and choose2 Scale elements were not present in every single trial, but only as part of a non-test, non-filler initial trial. The code for correct_which_results picks the answers to yesnocorrect, scalecorrect and whicharticle for every single trial and reports them as additional columns for the DashedSentence lines corresponding to the same trial.

    If you are not familiar with the dplyr package, you should read the documentation so you get a better sense of what the code above does. I also used the tidyr package because it contains the spread function that transforms pairs of columns from multiple rows into multiple columns on a single row.

    I tried also to have a column of the groups which defined by the PennElementName (TextInput2) but I got this message:
    Error: Each row of output must be identified by a unique combination of keys.
    Keys are shared for 144 rows:
    Although I deleted row number 10 because it has the same name (TextInput2) of row 11, but that did not solve the problem.

    This is basically the same problem: TextInput2 is only defined for trial #1, so you need to adapt the code to that. Also, you have two lines for TextInput2 for every participant, you only want to keep the second one, the one for which Parameter is Final.

    Jeremy

    in reply to: equal distribution of trial types before and after a break #6307
    Jeremy
    Keymaster

    Yes, replace rshuffle( ... , ... ) with randomize(seq( ... , ... ))

    Jeremy

    in reply to: MouseTracker recording wrong coordinates #6306
    Jeremy
    Keymaster

    Hi Irene,

    As it is now, the MouseTracker element only detects mouse movement, it does not detect mouse clicks at all. The content of the corresponding callback command is therefore run only when the cursor moves, and so your x/y variables are only updated on mouse movement, not on mouse click.

    Which means that what you log upon selection is not technically the mouse coordinates when the click happens but the mouse coordinates resulting from the latest movement. Because there typically is no mouse movement whatsoever with touchscreen devices (unless a mouse is plugged in, of course), I don’t understand how your x/y variables can ever be instantiated at all. Maybe the slight finger swipe that can come with tapping the screen is interpreted as a mouse movement…

    As I said, I don’t know what is happening exactly, so I don’t know how the different problems can be related. What I can say, however, is that the code from my previous message will effectively update clickx and clicky upon click, and no longer upon movement.

    I’m sorry, I wish I could give your more insight into this problem

    Jeremy

    in reply to: reaction time results appear in different two columns #6301
    Jeremy
    Keymaster

    Hi,

    You will need to do some more transformations on your data frames. Here is what you can do:

    # Set 'group' to non-null value for each participant
    require(dplyr)
    dashed_results <- dashed_results %>% 
      group_by(Time.results.were.received, MD5.hash.of.participant.s.IP.address) %>%
      mutate(group=max(group))
    
    # Select fields from all_results, make them columns per item, and merge with dashed_results
    require(tidyr)
    fields <- c("yesnocorrect","scalecorrect","whicharticle")
    correct_which_results <- subset(all_results, PennElementName%in%fields)
    correct_which_results <- correct_which_results %>% 
      group_by(Time.results.were.received, MD5.hash.of.participant.s.IP.address, Item.number) %>%
      select(Time.results.were.received, MD5.hash.of.participant.s.IP.address, Item.number, PennElementName, Value) %>%
      spread(., PennElementName, Value)
    dashed_results <- merge(dashed_results, correct_which_results,
          by=c("Time.results.were.received", "MD5.hash.of.participant.s.IP.address", "Item.number"))

    You’ll still have some NAs for whicharticle because you didn’t seem to have that Scale for your filler items.

    Jeremy

    • This reply was modified 4 years, 8 months ago by Jeremy. Reason: replaced tmp with dashed_results
    in reply to: equal distribution of trial types before and after a break #6300
    Jeremy
    Keymaster

    Hi,

    You can use the pick function, defined in this post:

    congruent = randomize("congruent");
    incongruent = randomize("incongruent");
    
    Sequence(
      rshuffle(pick(congruent,15),pick(incongruent,15))
      ,
      "break"
      ,
      rshuffle(pick(congruent,15),pick(incongruent,15))
    )

    Let me know if you have questions

    Jeremy

    in reply to: reaction time results appear in different two columns #6290
    Jeremy
    Keymaster

    Hi again,

    I took a look at your results file, and it turns out I was completely wrong about the spreadsheet editor issue. Given your results file, the code I gave you indeed fails to detect columns after the 13th one, because the first CSV line (ie. non-comment line) it encounters in the file has 13 columns.

    Fortunately there actually is a ready-made function from the tutorial that solves the problem: read.pcibex. So I inserted it to an adapted version of the code above, and it’s working now:

    read.pcibex <- function(filepath, auto.colnames=TRUE, fun.col=function(col,cols){cols[cols==col]<-paste(col,"Ibex",sep=".");return(cols)}) {
      n.cols <- max(count.fields(filepath,sep=",",quote=NULL),na.rm=TRUE)
      if (auto.colnames){
        cols <- c()
        con <- file(filepath, "r")
        while ( TRUE ) {
          line <- readLines(con, n = 1, warn=FALSE)
          if ( length(line) == 0) {
            break
          }
          m <- regmatches(line,regexec("^# (\\d+)\\. (.+)\\.$",line))[[1]]
          if (length(m) == 3) {
            index <- as.numeric(m[2])
            value <- m[3]
            if (index < length(cols)){
              cols <- c()
            }
            if (is.function(fun.col)){
              cols <- fun.col(value,cols)
            }
            cols[index] <- value
            if (index == n.cols){
              break
            }
          }
        }
        close(con)
        return(read.csv(filepath, comment.char="#", header=FALSE, col.names=cols))
      }
      else{
        return(read.csv(filepath, comment.char="#", header=FALSE, col.names=seq(1:n.cols)))
      }
    }
    
    # First read the results file
    all_results <- read.pcibex("resultsf")
    # We'll work on the DashedSentence lines only
    dashed_results <- all_results
    # Keep only the DashedSentence lines
    dashed_results <- subset(dashed_results, PennElementType=="Controller-DashedSentence")
    # Let us first make the columns character-based instead of factors
    cols.num <- seq(13,21)
    dashed_results[cols.num] <- sapply(dashed_results[cols.num],as.character)
    # Now we'll move the columns for the short lines (the ones without extra1 and extra2)
    short_lines <- dashed_results$Comments==""
    # Now let's move the columns
    wrong.cols <- seq(13,16)
    empty.cols <- seq(18,21)
    dashed_results[short_lines,empty.cols] <- dashed_results[short_lines,wrong.cols]
    dashed_results[short_lines,wrong.cols] <- NA
    # Done!

    Sorry for overlooking this problem, I shouldn’t have insisted it came from an editing process when you were clearly just following my advice

    Let me know if you have any questions

    Jeremy

    in reply to: log global vs. local variable #6288
    Jeremy
    Keymaster

    Hello Peiyao,

    Simply replace .settings.log() on your newVar elements with .global().set(0) and you’ll see the values reported at the end of all of the trial’s lines in the results file, without the cross-trial value contamination

    However you never create a Var element named choice so the line .log( "selected", getVar("choice")) will always report undefined. If having the selection reported in the line corresponding to your Selector element is not enough and you want it to also appear on every other lines as well, you’ll have to create a dedicated Var element and set it accordingly. You normally should be able to set that Var element by referring to the Selector element directly, but there seems to be a bug with recent versions of PennController, so you’ll need to test the Selector and set each value manually:

    // ...
    newVar("selection").global()
    ,
    newSelector("choice")
        .add( getImage("1") , getImage("2") , getImage("3") , getImage("4"))
        .callback( getTimer("timeLimit").test.ended().success(getVar("slowClick").set(1)) )
        .wait()
        .log()
        .test.selected(getImage('1')).success( getVar("selection").set(1) )
        .test.selected(getImage('2')).success( getVar("selection").set(2) )
        .test.selected(getImage('3')).success( getVar("selection").set(3) )
        .test.selected(getImage('4')).success( getVar("selection").set(4) )
    // ...

    Of course replace .log( "selected", getVar("choice")) with .log( "selected", getVar("selection")) (it’s better not to name two elements the same)

    Let me know if you have questions

    Jeremy

    in reply to: reaction time results appear in different two columns #6285
    Jeremy
    Keymaster

    Hi,

    I don’t see anything wrong with the lines you directly copied from your results file, so I suspect that the linebreaks visible in your screenshots are inserted by the software that you use to open the file. You do not need, and actually you probably should not, open the results file with a spreadsheet editor before analyzing it in R. When you’re in your project on the farm, simply click the eye icon under your results file to open its content in a new tab, and when you’re on that new tab, use your browser’s “Save as” (or “Save Page As”) option to save it on your local device. If you don’t enter a new filename, the file that gets saved should normally be simply named results, without any extension. Whether you add an extension or not to the filename, the content of the file is already comma-separated values (CSV), so there is no need to convert it or save it again after opening it in a spreadsheet editor. Just point to the unedited file you just saved with your browser from within the read.csv function in your R script, and I don’t see a reason why you should experience this problem.

    If you follow this procedure and still experience a problem, feel free to send me your results file at support@pcibex.net—I won’t share its content with anyone and will delete it immediately after troubleshooting your problem, but you only have my word for it, so make sure it is OK to send me your results file before doing it

    Jeremy

    in reply to: DashedAcceptabilityJudgment #6283
    Jeremy
    Keymaster

    Hello,

    There seems to be a bug with how PennController integrates the VBox controller, on which the DashedAcceptabilityJudgment controller relies. I’ll have to fix that for the next release of PennController. In the meantime, one solution would be to use the DashedSentence controller first and then directly code the judgment part in PennController:

    Template( "myTable.csv" ,
        // Row will iteratively point to every row in myTable.csv
      row => newTrial("experiment",
        newController("DashedSentence", {s: row.Sentence})
            .print()
            .log()
            .wait()
            .remove()
        ,
        newText("How acceptable was that sentence?").print()
        ,
        newScale(7)
            .before( newText("totally unacceptable ") )
            .after( newText(" totally acceptable ") )
            .button()
            .keys()
            .print()
            .log()
            .wait()
      )
    )

    Fiddle with the aesthetics if the scale’s rendering is not to your liking

    Let me know if you have questions

    Jeremy

    in reply to: MouseTracker recording wrong coordinates #6277
    Jeremy
    Keymaster

    Hi Irene,

    I’m sorry for not getting back to your sooner. Unfortunately, I’m still unable to identify the source of your problem. However, I realized something in the meantime, which is that smartphone users typically don’t connect a mouse to their device, but rather directly tap their screen: it makes me wonder how you manage to get coordinates at all for them, given that your script uses a MouseTracker element, which ultimately tracks mouse movements, not clicks (or taps, in the case of smartphones).

    To add to the mystery, clientY (which is what the MouseTracker element reports) should never exceed the viewport’s height, which means that investigating possible scrolling-related issues is a dead end anyway.

    I apologize for suggesting to use a MouseTracker element to track click coordinates. If you were to re-run your study, I’d now suggest you use a Function element to insert a plain javascript function that will better track clicks, like this:

    newTrial(
        newCanvas("content", "50vw","50vh")
            .css("background-color", "orange")
            .print("center at 50vw", "middle at 50vh")
        ,
        newVar("clickx",[]).log(),newVar("clicky",[]).log()
        ,
        newFunction( ()=>$(".PennController-content").click( e=>{
           getVar("clickx").set( v=>[...v,e.clientX] )._runPromises();
           getVar("clicky").set( v=>[...v,e.clientY] )._runPromises();
        }) ).call()
        ,
        newSelector().add(getCanvas("content")).wait().wait()
        ,
        getVar("clickx").set( v=>v.join('.') ),
        getVar("clicky").set( v=>v.join('.') )
    )

    Let me know if you make any progress on this issue, I’d like to fix any related bugs in PennController to prevent it from happening again in the future

    Jeremy

    in reply to: reaction time results appear in different two columns #6276
    Jeremy
    Keymaster

    Hi,

    Yes, you can upload your screenshot here, for example: https://onpaste.com/
    Then use the img button when you write your message here to paste the image’s URL

    Could you open your results file in a simple text editor (or even directly in your project on the farm) and paste the two results lines here?

    Jeremy

    in reply to: uploadRecordingsError not working? #6275
    Jeremy
    Keymaster

    Hi Masato,

    You’re right, of course. I edited my message, it should now display > instead of $gt;

    Jeremy

Viewing 15 posts - 1,051 through 1,065 (of 1,522 total)