Can we randomize time with newTimer() ?

PennController for IBEX Forums Support Can we randomize time with newTimer() ?

Viewing 14 posts - 46 through 59 (of 59 total)
  • Author
    Posts
  • #7962
    Larissa_Cury
    Participant

    Dear Jeremy,

    but I don’t think that I put the accuracy var on this page. Let me show it to you: this is the “instructions_E” page =>

    newTrial("instructions_E",
      newText("instructions-12","Você está pronto?")
        .cssContainer({
            "border": "5px solid black",
            "background-color": "yellow",
            "color": "black",
            "font-size":"50px"
        })
        .center()
        .print()
      ,
      newText("instructions-17","<p>Sinta-se livre para fazer uma pausa agora</p>")
        .cssContainer({
            "font-size":"22px",
            "text-align": "center"
        })
        .center()
        .print()
      ,
      newImage("boy-image","boy.png")
        .size(200,200)
        .center()
        .print()
      ,
      newText("instructions-14","<p><center> Se você quiser praticar de novo, clique aqui:")
        .cssContainer({
            "font-size":"22px",
            "text-align": "center"
        })
        .center()
        .print()
     ,
      newButton("come back","PRATICAR DE NOVO")
        .callback(newVar("practiceRTs").global().set( [] ),jump(startsWith("p_trial")) , end() ) 
        .css("margin","1.5em")
        .center()
        .print()
      ,
      newText("instructions-blocks","<p><center>A tarefa terá 3 blocos. <b style=color:red;>Cada bloco dura aproximadamente 5 minutos.</b> No total, você deve demorar 15 minutos.</p></center>")
        .cssContainer({
            "font-size":"22px",
            "text-align": "center",
            "white-space":"nowrap"})
        .center()
        .print()
      ,
      newText("instructions-15","<p><center>Quando você se sentir <b style=color:red;>PRONTO</b>, clique no botão abaixo:</p></center>")
        .cssContainer({
            "font-size":"22px",
            "text-align": "center"
        })
        .center()
        .print()
      ,
      newButton("wait","COMEÇAR")
        .center()
        .print()
        .wait()
    );

    the page that shows the feedback is the previous one of Instructions_E, this one here:

    newTrial("feedback-trial",
    defaultText
            .print()
    ,
    newText("feedback-text","Seus resultados:")
    .cssContainer({
        "border": "5px solid black",
        "background-color": "yellow",
        "color": "black",
        "margin":"1em",
        "font-size":"50px"})
        .center()
    ,
      newVar("timeText").set( getVar("practiceRTs").global() ).set(v=> "Você demorou "+(v.reduce((n,m)=>n+m)/v.length)+"ms por pergunta em média" ),
      newText( "feedbackTime" ).text( getVar("timeText") ).print()
      .cssContainer({
        "font-size":"22px",
        "text-align": "left",
        "white-space":"nowrap"})
      ,
      newVar("accuracyText").set( getVar("accurate").global() ).set(v=> "Você acertou "+v.filter(a=>a==true).length+" do total de "+v.length ),
      newText( "feedbackAccuracy" ).text( getVar("accuracyText") ).print()
      .cssContainer({
        "font-size":"22px",
        "text-align": "left",
        "white-space":"nowrap"})
      ,
      newButton("CONTINUAR")
      .center()
      .cssContainer({"margin":"1em"})
      .print()
      .wait()
    );

    So the sequence is this: instructions + practice trial with feedback within + final feedback + instructions_E

    should I add the accuracy inside the callbutton? Like this:

      newButton("come back","PRATICAR DE NOVO")
        .callback(newVar("practiceRTs").global().set( [] ),newVar("accurate").global().set( [] ),jump(startsWith("p_trial")) , end() ) 
        .css("margin","1.5em")
        .center()
        .print()

    would that work?

    #7963
    Jeremy
    Keymaster

    Yes: if you want to reset both Var elements before going back to the beginning of the p_trial sequence of trials, you need to call set on both before jump in the callback command

    Jeremy

    #7964
    Larissa_Cury
    Participant

    Dear Jeremy,

    I’ve already made this change and it worked nicely! Thank you once more!

    #7969
    Larissa_Cury
    Participant

    Dear Jeremy,
    My R code was running just fine for this same code before I had to make the timing alterations. My guess is that before the timeout alteration, I had to had a pressed key such as S or K, but now, because of the required timeout, it is not necessarialy anymore…I guess that the code is struggling with the NAs. Would you have any recommendations?

    This is an example results file from the code with the timing alterations => https://github.com/LariCury/Sample-results.git

    ##install.packages("ddlyr","tidyverse")
    library(dplyr)
    library(tidyverse)
    library(writexl)
    
    #Read PciBex's function
    
    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 (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)))
      }
    }
    
    # Read in results file
    results <- read.pcibex("Result_Example.csv")
    
    add_blocks <- function (df,id) {
      PRACTICE_TO_FIRST <- max(df$EventTime[df$Label=="instructions_E"])
      FIRST_TO_SECOND <- max(df$EventTime[df$Label=="instructions_F"])
      SECOND_TO_THIRD <- max(df$EventTime[df$Label=="instructions_G"])
      df$block <- 0
      df$block[df$EventTime>PRACTICE_TO_FIRST] <- 1
      df$block[df$EventTime>FIRST_TO_SECOND] <- 2
      df$block[df$EventTime>SECOND_TO_THIRD] <- 3
      return(df)
    }
    results_blocks <- results %>%
      group_by(id) %>%
      group_modify(add_blocks)
    
    ##the DF name is results_blocks
    #Filter the relevant collumns and create the Reaction_Time collumn
    
    data_results <- results_blocks %>%
      filter(Parameter %in% c("Print","PressedKey")) %>% 
      select(id,Label,imagens,block,Value,EventTime,Parameter) %>% 
      group_by(id) %>% 
      
      mutate(event = case_when(Parameter == "Print" ~ "Time1",
                               Parameter == "PressedKey" ~ "Time2")) %>%   
      
      ungroup() %>% 
      #select(-Parameter) %>% 
      pivot_wider(names_from = event, values_from = EventTime)    
    
    ## Omit NA from Time2 and Time1:
      
      a <- na.omit(data_results$Time2)
      b <- na.omit(data_results$Time1)
      
    ## Reaction_Time = Time2-Time1: 
      
    RT <- a-b
      
    ## Create the REACTION_TIME collumn:
      
    data_results_final <- data_results %>% 
        filter(Value %in% c("S","K"))  %>% 
        
    data_results_final$newRT <- RT  
        
    ## Omit irrelevant colluns (Time1 and Time2)  
    
    clean_data <-  subset(data_results_final, select = -c(Time1,Time2))

    This is an example results file from the code with the timing alterations => https://github.com/LariCury/Sample-results.git

    • This reply was modified 2 years, 6 months ago by Larissa_Cury. Reason: typo
    #7971
    Larissa_Cury
    Participant

    add =>

    I’ve just found something funny, I counted both older (working) and the new (not working) versions, and the output were quite interesting =>

    my_count <- data_results %>% 
                count(Label, block) %>% 
                group_by(Label)

    In the older version, I get this => https://drive.google.com/file/d/1ENUnc-zm1QLQWLLPPF3QClNZtWNefV-1/view?usp=sharing

    In the new version, I get this => https://drive.google.com/file/d/1EqryhXxTo9jrNxxOFVtjhDpwQ2_0QUe1/view?usp=sharing

    ps: I forgot to say that the older version had E and I as the keys and now I have S and K, I’ve upload in my github an example of results file of the older version as well, which is working just fine

    (https://farm.pcibex.net/r/mGDSNL/)

    I’m trying to understand what messed the count, I was thinking that the Nas were the matter…

    • This reply was modified 2 years, 6 months ago by Larissa_Cury. Reason: add my code link
    #7973
    Larissa_Cury
    Participant

    Just an update =>

    I figure it out that the problem was that when there’s no pressed key, there’s no EventTime for that as well, then R couldn’t work properly…So I’ve research a lot here on the forum and on the documentation and I came up with the solution of adding a var element to compute my reaction time (below) which is working just fine! My only problem is that now I cannot label the trials according to my blocks, the labeling is all messed around, let me show it to you:

    new (https://farm.pcibex.net/r/XSJAnP/)

    newVar("RT").global().set( v => Date.now() )   <-------------- this is working just fine I guess =)
    ,
        newKey("keypress1","SK")
            .log()
            .callback( getTimer("timer-RT").stop() )
        ,
        getTimer("timer-RT").wait()
    ,
        getVar("RT").set( v => Date.now() - v )
    ....
    .log( "ReactionTime" , getVar("RT") )

    In R:

    #Read PciBex's function
    
    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 (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)))
      }
    }
    
    # Read in results file
    results <- read.pcibex("results (11).csv")
    
    ### add function                                                 <-------------- sth not quite right (maybe because now the EventTime has "never" as valuues, but I don't 
                                                                                                                    know how to fix it :(
    add_blocks <- function (df,id) {
      PRACTICE_TO_FIRST <- max(df$EventTime[df$Label=="instructions_E"])
      FIRST_TO_SECOND <- max(df$EventTime[df$Label=="instructions_F"])
      SECOND_TO_THIRD <- max(df$EventTime[df$Label=="instructions_G"])
      df$block <- 0
      df$block[df$EventTime>PRACTICE_TO_FIRST] <- 1
      df$block[df$EventTime>FIRST_TO_SECOND] <- 2
      df$block[df$EventTime>SECOND_TO_THIRD] <- 3
      return(df)
    }
    
    ###add blocks with the new function
    
    results_blocks <- results %>%
      group_by(id) %>%
      group_modify(add_blocks)
    
    ######################################################## my new filter 
    
    data_results <- results_blocks %>%
      filter(Parameter %in% c("Key","PressedKey")) %>%
      select(id,Label,imagens,Value,Parameter,ReactionTime,block) %>%
      group_by(id) %>%
      mutate(Answer = case_when(is.na(Value) ~ "0",
                                Value == "S" ~ "S",
                                Value == "K" ~ "K")) %>%
      select(-Value) %>%
      select(id,Label,imagens,Answer,ReactionTime,block)

    This result file is here => (results (11)) => https://github.com/LariCury/Sample-results.git

    I should have 96 items per block, but I guess that the missing values on EventTime are messing the count, I just don’t know how to fix it…Do you have any suggestion?

    Best,

    • This reply was modified 2 years, 6 months ago by Larissa_Cury. Reason: add information
    #7975
    Jeremy
    Keymaster

    Hi Larissa,

    One issue is that you have at least one case where the log command of the Key element is missing "all" (at least in the current code at https://farm.pcibex.net/r/XSJAnP/, where it concerns the trials labeled “trial_1_no_cue_DOWN”)

    In the absence of a keypress, the line will have Key as its parameter instead of PressedKey, NA as its value and Never in the EventTime column. So filter(Parameter %in% c("Key","PressedKey")) %>% will exclude those lines where the participant never pressed a key. Try replacing it with filter(Parameter %in% c("Key","PressedKey","Key")) %>%

    I’m not sure how to handle the block issue for now. You are correct: having NAs in place of timestamps messes with the block column and will assign block 0 to those NA rows. One solution would be to use the linear order of the rows to assign blocks rather than just the EventTime column, but I can’t think of an immediate way of doing it off the top of my head

    Jeremy

    #7977
    Larissa_Cury
    Participant

    Dear Jeremy,
    Thank you for your kind answer as always! Well, I’ve tried many many many things but none of them seemed to work, but, then, I came up with this very crazy idea that seems to be working just fine!

    Basically, I thought “well, the function counts max values of EventTime, since the “nevers” are there, it’s not getting quite right”…So I created a new column with 1: up to the n rows and it seems to be working just fine, let me show it to you. It seems to be labelling the trials accurately, is it, indeed?

    # Read in results file
    results <- read.pcibex("results (12).csv")
    
    ############################################### create new collumn "Randowm" with 1:n(row)#####################################
     results1 <- results %>%
                           mutate(Random = as.numeric(seq(1:n()))
       )
    
    ###########################function#################################################################
    
    add_blocks <- function (df,id) {
      PRACTICE_TO_FIRST <- max(df$Random[df$Label=="instructions_E"]) <--------------------I've changed the reference column 
      FIRST_TO_SECOND <- max(df$Random[df$Label=="instructions_F"])
      SECOND_TO_THIRD <- max(df$Random[df$Label=="instructions_G"])
      df$block <- 0
      df$block[df$Random>PRACTICE_TO_FIRST] <- 1
      df$block[df$Random>FIRST_TO_SECOND] <- 2
      df$block[df$Random>SECOND_TO_THIRD] <- 3
      return(df)
    }
    
    results_blocks <- results1 %>%
      group_by(id) %>%
      group_modify(add_blocks)
    
    ########## filter the relevant columns and transform the answer column ########################################
    
    data_results <- results_blocks %>%
      filter(Parameter %in% c("Key","PressedKey","Key")) %>%
      select(id,Label,imagens,Value,Parameter,ReactionTime,block) %>%
      group_by(id) %>%
      mutate(Answer = case_when(is.na(Value) ~ "0",
                                Value == "S" ~ "S",
                                Value == "K" ~ "K")) %>%
      select(-Value) %>%
      select(id,Label,imagens,Answer,ReactionTime,block)
    
    ---

    This results file 12 can be seen here => https://github.com/LariCury/Sample-results.git
    The output of this code is called “Exemplo_Resultados”, it’s also on my git 🙂


    I’m just wondering sth, I tried to create a Var element in order to capture the timing from this Var instead of EventTime, but it didn’t work, let me show it to you => https://farm.pcibex.net/r/MVMhVB/
    I’ve set the var on Instructions_E and called it back on a new trial called “”blocks-timer-trial”)…why didn’t it log? shouldn’t it?

    best,

    #7979
    Jeremy
    Keymaster

    Hi,

    Yes, you got it, that’s precisely the direction I had in mind when I suggested using the linear order of the rows rather than timestamps. Your solution seems to work beautifully

    Re. your Var element: you correctly create it as a .global Var element at the end of the trial labeled “instructions_E” but when you refer back to it at the end of the trial labeled “blocks-timer-trial” you forget to call .global() again, so PennController cannot access the value of the Var element that you created in a previous trial. Then you call .log( "BlocksTimer" , getVar("BLOCKS") ) on that same element, so you might have one results line for that trial (the one labeled “blocks-timer-trial”) that will report the value of the Var element. But given the two arguments you passed to .log, I think you meant to add a column rather than a row. If so, you need to call log on the closing parenthesis of newTrial() rather than on the Var element itself

    Jeremy

    #7983
    Larissa_Cury
    Participant

    Dear Jeremy!
    I’m so so happy it worked!!!!! Thank you for your feedback!!!

    Ohhhh, concerning the Var element…oh, all right. Yeah, you got my idea, which was to try to create a new collumn which would have the timers from Instructions_E up to the end of the experiment, so that then I could make the function in R use it as its parameter, but now that the 1:n() solution is working, I don’t think that adding a new Var is the best option, right? I guess that it is making the experiment kinda slower…but, If I did include that, would it look sth like this?

    newTrial("blocks-timer-trial",
    newText("blocks-text","Espere...")
    .cssContainer({
        "font-size":"30px",
        "position": "absolute",
        "margin-top": "255px",    //places it in the middle of the screen 
        "white-space": "nowrap"})
    .center()
    .print()
    ,
        newTimer("blocks-text-timer",1500)
        .start()
        .wait()
    ,
      getText("blocks-text").remove()
    ,
     getVar("BLOCKS").global().set( v => Date.now() - v )
    ,                                                     ->......... it returns me an error when I try to separate them
    .log( "BlocksTimer" , getVar("BLOCKS") )
    );
    #7984
    Jeremy
    Keymaster

    Hi,

    Indeed, you won’t need to use the Var method now that you’ve fixed the EventTime issue in R

    .log is not a global PennController command: you either call it on a PennController element or on the closing parenthesis of a newTrial command. In either case, .log comes immediately after a closing parenthesis (ignoring any space or linebreak character separating the parentehsis and the period). You get an error because you wrote .log after a comma, the way you would insert a reference to an element using newX or getX

    This is how you would call .log on the closing parenthesis of newTrial:

    newTrial("blocks-timer-trial",
      newText("blocks-text","Espere...")
        .cssContainer({
          "font-size":"30px",
          "position": "absolute",
          "margin-top": "255px",    //places it in the middle of the screen 
          "white-space": "nowrap"})
        .center()
        .print()
      ,
      newTimer("blocks-text-timer",1500)
        .start()
        .wait()
      ,
      getText("blocks-text").remove()
      ,
      getVar("BLOCKS").global().set( v => Date.now() - v )
    )
    .log( "BlocksTimer" , getVar("BLOCKS") )
    

    Jeremy

    #7985
    Larissa_Cury
    Participant

    Ohhhhhhhhhh, now I got it! Thank you, Jeremy, once more!!! 😀

    I have a question that’s not related to the timing, so if it’s better I can open a new forum discussion for that (let me known 🙂 ) which is: there isn’t a problem if two or more participants take the experiment at once, right? Supposly, a class of students each with his/hers own computer?

    #7986
    Jeremy
    Keymaster

    It won’t be a problem that multiple participants take the the experiment at the same time: all the scripts and resources start loading at the beginning of the experiment (when the link is open) and then everything is executed locally, on the participant’s machine. Only when the end of the experiment is reached is the server contacted again, to submit the responses. The two first columns in the results file will report a timestamp for when the responses were received and a sequence of letters and digits unique to the browser and IP of the participant. It is quite unlikely that two students would submit at the exact same millisecond, but even if so, if each student uses a different device, the second column should report a different value anyway

    Jeremy

    #7987
    Larissa_Cury
    Participant

    Got it!!! I always say this, but, honestly, I can never thank you enough, Jeremy. Thank you for following me throughout this post so willingly to help me ❤ I hope I don’t come up with any more surprises 😅

Viewing 14 posts - 46 through 59 (of 59 total)
  • You must be logged in to reply to this topic.