Comments (14)
Hi Bonnie,
I would actually hold off on using the velocity function. I am going to incorporate Ronen's blink algo which does not require thresholds to be passed: https://link.springer.com/article/10.3758/s13428-017-1008-1. I will probably push that sometime in the next week or so.
mutate(extendpupil=extend_blinks(blinks_pupil, fillback=fillback, fillforward=fillforward, hz=hz)) %>%
You are correct! I should not have defined it again :)
Moreover, I am wondering if blink extension and interpolation need to be incorporated in this function at all... I find it odd not to give the choice of interpolation type (linear or cubic) or max gap which you have incorporated into the interpolation function.
This was roughly based on something Sebastiaan did in his blink paper. I could not quite capture what he did in that paper so I opted for a basic velocity measure. It is not the most elegant and I think Ronen's algo is a bit better and does not require interpolation or extending the blinks.
I do agree with you that interpolation should probably be taken out.
from gazer.
How is a basic velocity measure working for your group? I would be interested to know.
from gazer.
In this vignette I do separate them: https://github.com/dmirman/gazer/blob/master/vignettes/blink_detection.Rmd.
Not sure why I combined them.
from gazer.
oh great! Thanks for the clarity. I looked over Sebastiaan's paper and couldn't quite understand how you got here. We have not implemented velocity in our pipeline. I just starting working today to compare all of the options out there to see which we want to use moving forward. I started with what was implemented in Gazer (NA+extension, blink velocity+extension, MAD+extension) and then moved on to other options out there (Hampel filter, Ronens, etc.). I have the R code from osf for the noised based algo. Do you think you will change it substantially (other than fitting it to gazer format)?
I'm get justing the code down and then will run some tests. I'll let you know how they go!
from gazer.
When did you last download Ronen's code? I actually worked with him and Paul a month ago to fix some errors. I also wrote a bit of code to actually use the function.
from gazer.
I do not plan to change the function much. I will actually probably share my vignette/blog on how to use it with gazeR as well.
from gazer.
Just checked- I have the most up to date version of the code. Let me know when you post it. I was able to test it for one trial but I haven't had the chance to edit it to be able to run it grouped by subject x trial. Although I do not have an example to point to, I imagine there may be times where blinks are recorded with these sharp changes without having missing data. I think one draw back to their approach is the reliance on missing data.
from gazer.
Below is some code that will help you on your journey.
#this applies the noise function to each trail by subject
df_blinks<-interp_graph %>%
dplyr::group_by(subject, trial) %>%
dplyr::summarise(Blink_Index = list(noise_based_blink_detection(as.matrix(interp_graph$pupil), 250))) %>%
unnest(c(Blink_Index))
The noise_based_blink_detection should be included in gazeR now.
#this will merge the blink data to your main df/tibble which is interp_graph above
i1 <- match(interp_graph$time, df_blinks$Blink_Index) # need to match on time and not index to correspond to sampling rate
interp_graph[names(df_blinks)[1:2]] <- lapply(df_blinks[1:2], `[`, i1)
# once merged onsets must be duplicated across until offset in order to mark as blinks
blinks <- interp_graph %>%
dplyr::group_by(grp = cumsum(!is.na(Label))) %>%
dplyr::mutate(Label = replace(Label, first(Label) == 'Onset', 'Onset')) %>%
dplyr::mutate(Blinks_New=ifelse(Label=="Onset" | Label=="Offset", 1, 0)) %>% #turn Onset and Offset 1
mutate(Blinks_New=ifelse(is.na(Blinks_New), 0, Blinks_New)) %>% # turn rest of values 0
dplyr::ungroup()
Blink_Pupil<- blinks %>%
group_by(subject, trial) %>%
mutate(blinks_pupil=ifelse(Blinks_New==1, pupil==NA, pupil)) %>%
mutate(blinks_pupil=ifelse(blinks_pupil==0, NA, blinks_pupil))
from gazer.
Hi!
I cannot make the code from your last comment work. The first part workers, but merging the blink data with previous data does not. There is also no column called "Label" with values "Onset" and "Offset" - I am not sure where should this come from? Also, when I try to match and make "i1" it results in NAs with length nrow(interp_graph). Is there a way around this?
Best,
Ziva
from gazer.
Hi,
Have a look at this document. I want to say that I did not write this code and have not had time to extensively validate it. IMHO I would probably use the forward and backward fill method to treat blinks and then interpolate.
The algo is from here: https://pubmed.ncbi.nlm.nih.gov/29340968/
from gazer.
Hi Jason & Ziva
The pdf fills in a few missing pieces but it still fails when trying to apply the function across subject and trials. My issue was that blinks that occurred in one trial were repeated for every other trial. Below is my fix (see points 2 & 4).
I agree that the forward and backward fill method is a good way to treat blinks. That is the method my group uses and will likely continue to use.
bz
- You have to move NAs back to 0 in the pupil column (ew)
pupil_files <- pupil_files %>%
dplyr::mutate(pupil=ifelse(is.na(pupil), 0, pupil))
- DIFFERENT THAN ABOVE - Do not include the datafile when passing the pupil column in the noise detection function.
df_blinks <- pupil_files %>%
group_by(subject, trial) %>%
dplyr::summarise(Blink_Index= list(noise_based_blink_detection(as.matrix(pupil), 1000))) %>%
unnest(c(Blink_Index))
- Assign labels to the blink index
df_blinks$Label <- rep(c("Onset", "Offset"), length.out=nrow(df_blinks))
- DIFFERENT THAN ABOVE -use dplyr left_join function to match blink index and time (so to include subject and trial)
pupil_files <- left_join(pupil_files, df_blinks, by=c("subject", "trial", c("time"="Blink_Index")))
- The rest of the code you provided worked for me.
###---------- CODE from JGeller: WORKING ----------###
blinks <- pupil_files %>%
dplyr::group_by(grp = cumsum(!is.na(Label))) %>%
dplyr::mutate(Label = replace(Label, first(Label) == 'Onset', 'Onset')) %>%
dplyr::mutate(Blinks_New=ifelse(Label=="Onset" | Label=="Offset", 1, 0)) %>% #turn Onset and Offset 1
mutate(Blinks_New=ifelse(is.na(Blinks_New), 0, Blinks_New)) %>% # turn rest of values 0
dplyr::ungroup()
Blink_Pupil<- blinks %>%
group_by(subject, trial) %>%
mutate(blinks_pupil=ifelse(Blinks_New==1, pupil==NA, pupil)) %>%
mutate(blinks_pupil=ifelse(blinks_pupil==0, NA, blinks_pupil))
- You can plot a trial to test if its working
###---------- Plot Blinks ----------###
blink_graph <- Blink_Pupil %>%
dplyr::filter(subject=="YOUR SUBJECT", trial=="YOUR TRIAL")
bold <- element_text(face = "bold", color = "black", size = 14) #axis bold
#Graph
pup_g<- ggplot(blink_graph, aes(x=time, y= pupil)) + geom_point() +
geom_line(aes(x=time, y=blinks_pupil), colour="green") + xlab("Time (ms)") + ylab("Pupil Size (arbitrary units)") + theme_bw() + theme(axis.title.y=element_text(size = 16, face="bold"), axis.title.x = element_text(size=16, face="bold"), axis.text.x=element_text(size = 12, face="bold"), axis.text.y=element_text(size=12, face="bold"))
print(pup_g)
- Move on to interpolation
from gazer.
Thanks for looking into this @bzuck-temple :). I'm glad you fixed some of the kinks. Did you ever figure out what the best method was?
from gazer.
@bzuck-temple can share how the noise algo worked on your data? In my sample data I had some artifacts and it didn’t do a great job.
from gazer.
Anecdotally, I found that it struggled with marking the offset. It kept more of what I would identify as part of the blink than I would have liked.
I only compared the methods visually- never got around to doing a systematic comparison.
from gazer.
Related Issues (20)
- GazeR functions exceed my working space limit: how to downsample HOT 12
- Can GazeR process datasets of the task which is implemented using MATLAB? HOT 2
- parse_edf function deletes message entries on the way HOT 3
- Cannot either install or download the GazeR package(s) HOT 11
- parse_edf function creates more trials than actually present HOT 11
- unable to use edfR HOT 14
- Downsample XY for Pupil
- sample_message to message not updated in merge_pupil HOT 1
- unable to install saccades and edfR HOT 15
- Baseline correction problem HOT 5
- Loading edfs on Code Ocean HOT 28
- Read pupil data from excel HOT 7
- Error when running dplyr::gather HOT 2
- issues edfR HOT 14
- error using the downsample_gaze function HOT 5
- Accommodating data timebinned in Eyelink HOT 2
- downsample_gaze not found HOT 13
- Can GazeR analyze eye movement data in virtual reality environments? HOT 10
- How to find the peak pupil size and a possible bug in remove missing data? HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gazer.