PennController for IBEX › Forums › Support › Can we randomize time with newTimer() ?
- This topic has 58 replies, 2 voices, and was last updated 2 years, 6 months ago by Larissa_Cury.
-
AuthorPosts
-
March 23, 2022 at 2:10 pm #7962Larissa_CuryParticipant
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?
March 23, 2022 at 2:14 pm #7963JeremyKeymasterYes: 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 beforejump
in thecallback
commandJeremy
March 23, 2022 at 2:23 pm #7964Larissa_CuryParticipantDear Jeremy,
I’ve already made this change and it worked nicely! Thank you once more!
March 24, 2022 at 7:37 am #7969Larissa_CuryParticipantDear 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
March 24, 2022 at 8:50 am #7971Larissa_CuryParticipantadd =>
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
March 24, 2022 at 8:36 pm #7973Larissa_CuryParticipantJust 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
March 25, 2022 at 3:03 pm #7975JeremyKeymasterHi 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 ofPressedKey
,NA
as its value andNever
in the EventTime column. Sofilter(Parameter %in% c("Key","PressedKey")) %>%
will exclude those lines where the participant never pressed a key. Try replacing it withfilter(Parameter %in% c("Key","PressedKey","Key")) %>%
I’m not sure how to handle the block issue for now. You are correct: having
NA
s 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 headJeremy
March 28, 2022 at 7:48 am #7977Larissa_CuryParticipantDear 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,
March 28, 2022 at 9:38 am #7979JeremyKeymasterHi,
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 calllog
on the closing parenthesis ofnewTrial()
rather than on the Var element itselfJeremy
March 28, 2022 at 5:28 pm #7983Larissa_CuryParticipantDear 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") ) );
March 28, 2022 at 5:37 pm #7984JeremyKeymasterHi,
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 anewTrial
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 usingnewX
orgetX
This is how you would call
.log
on the closing parenthesis ofnewTrial
: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
March 28, 2022 at 6:09 pm #7985Larissa_CuryParticipantOhhhhhhhhhh, 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?
March 28, 2022 at 6:17 pm #7986JeremyKeymasterIt 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
March 28, 2022 at 6:22 pm #7987Larissa_CuryParticipantGot 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 😅
-
AuthorPosts
- You must be logged in to reply to this topic.