-
Notifications
You must be signed in to change notification settings - Fork 76
Add day segment analyses to GGIR part5 for WW and OO defined days #1525
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
47af50e
debdea6
ab81021
1a8e05d
58f830a
c8b7c3e
5055a74
9ca48a0
652eae8
f489489
d326280
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -503,16 +503,20 @@ g.part5 = function(datadir = c(), metadatadir = c(), f0=c(), f1=c(), | |
| for (si in next_si:(next_si + length(segments) - 1)) { | ||
| fi = 1 | ||
| current_segment_i = si - next_si + 1 | ||
| segStart = segments[[current_segment_i]][1] | ||
| segEnd = segments[[current_segment_i]][2] | ||
| Nindices = length(segments[[current_segment_i]]) | ||
| segStart = segments[[current_segment_i]][seq(1, Nindices, by = 2)] | ||
| segEnd = segments[[current_segment_i]][seq(2, Nindices, by = 2)] | ||
| Nsegments = pmin(length(segStart), length(segEnd)) | ||
| extraRowsNeeded = max(c(si, di)) - nrow(dsummary) | ||
| if (extraRowsNeeded > 0) { | ||
| dsummary = rbind(dsummary, matrix(data = "", nrow = extraRowsNeeded, ncol = ncol(dsummary))) | ||
| } | ||
| if (timewindowi == "MM" & si > 1) { # because first segment is always full window | ||
| if (timewindowi %in% c("MM", "WW") & si > 1) { # because first segment is always full window | ||
| if (("segment" %in% colnames(ts)) == FALSE) ts$segment = NA | ||
| if (!is.na(segStart) && !is.na(segEnd)) { | ||
| ts$segment[segStart:segEnd] = si | ||
| for (gi in 1:Nsegments) { | ||
| if (!is.na(segStart[gi]) && !is.na(segEnd[gi])) { | ||
| ts$segment[segStart[gi]:segEnd[gi]] = si | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a segment occurs twice within the same biological window (e.g., in a Against my expectations:
Is it the intended design of this branch to merge recurring segments within extended windows, or should each segment be treated as a distinct entry in the subsequent analysis?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is intentional to achieve a constant number of segments across individuals. |
||
| } | ||
| } | ||
| } | ||
| # Already store basic information about the file | ||
|
|
@@ -788,7 +792,8 @@ g.part5 = function(datadir = c(), metadatadir = c(), f0=c(), f1=c(), | |
| "g.part5.savetimeseries", "g.part5.wakesleepwindows", | ||
| "g.part5.onsetwaketiming", "g.part5_analyseSegment", | ||
| "g.part5_initialise_ts", "g.part5.analyseRest", | ||
| "g.fragmentation", "g.intensitygradient") | ||
| "g.fragmentation", "g.intensitygradient", | ||
| "g.part4_extractid", "markerButtonForRest") | ||
| errhand = 'stop' | ||
| } | ||
| i = 0 # declare i because foreach uses it, without declaring it | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,61 +64,6 @@ g.part5.definedays = function(nightsi, wi, indjump, epochSize, qqq_backup = c(), | |
| qqq[2] = Nts | ||
| lastDay = TRUE | ||
| } | ||
| qqq_backup = qqq | ||
| # in MM, also define segments of the day based on qwindow | ||
| if (!is.na(qqq[1]) & !is.na(qqq[2])) { | ||
| segments_timing = NULL | ||
| if (qqq[2] > Nts) qqq[2] = Nts | ||
| fullQqq = qqq[1]:qqq[2] | ||
| firstepoch = format(ts$time[qqq[1]], "%H:%M:%S") | ||
| lastepoch = format(ts$time[qqq[2]], "%H:%M:%S") | ||
| qnames = NULL | ||
| if (is.data.frame(qwindow)) { | ||
| date_of_interest = substr(ts$time[qqq[1]], 1, 10) | ||
| qdate = which(qwindow$ID == ID & qwindow$date == date_of_interest) | ||
| if (length(qdate) == 1) { # if ID/date matched with activity log | ||
| qnames = unlist(qwindow$qwindow_names[qdate]) | ||
| qwindow = unlist(qwindow$qwindow_values[qdate]) | ||
| qwindow_order = order(qwindow) | ||
| qwindow = qwindow[qwindow_order] | ||
| qnames = qnames[qwindow_order] | ||
| } else { # if ID/date not correctly matched with activity log | ||
| qwindow = c(0, 24) | ||
| } | ||
| } else { | ||
| qwindow = sort(qwindow) | ||
| if (qwindow[1] != 0) qwindow = c(0, qwindow) | ||
| if (qwindow[length(qwindow)] != 24) qwindow = c(qwindow, 24) | ||
| } | ||
| # define segments timing in H:M:S format | ||
| breaks = qwindow2timestamp(qwindow, epochSize) | ||
| startOfSegments = breaks[-length(breaks)] | ||
| endOfSegments = subtractEpochFromTimeName(breaks[-1], epochSize) | ||
| if (length(startOfSegments) > 1) { # when qwindow segments are defined, add fullwindow at the beginning | ||
| startOfSegments = c(firstepoch, startOfSegments) | ||
| endOfSegments = c(lastepoch, endOfSegments) | ||
| } | ||
| segments_timing = paste(startOfSegments, endOfSegments, sep = "-") | ||
| # define segment names based on qnames or segmentX | ||
| if (is.null(qnames)) { | ||
| segments_names = paste0("segment", 0:(length(segments_timing) - 1)) | ||
| segments_names = gsub("segment0", "MM", segments_names) | ||
| } else { | ||
| segments_names = c("MM", paste(qnames[-length(qnames)], qnames[-1], sep = "-")) | ||
| } | ||
| # Get indices in ts for segments start and end limits | ||
| hms = format(ts$time[fullQqq], format = "%H:%M:%S") | ||
| segments = vector("list", length = length(segments_timing)) | ||
| names(segments) = segments_timing | ||
| for (si in 1:length(segments_timing)) { | ||
| s0s1 = unlist(strsplit(segments_timing[si], split = "[-]")) | ||
| s0s1 = format(s0s1, format = "%H:%M:%S") | ||
| # tryCatch is needed in the case that the segment is not available in ts, | ||
| # then a no non-missing values warning would be triggered by the which function | ||
| segments[[si]] = tryCatch(range(fullQqq[which(hms >= s0s1[1] & hms <= s0s1[2])]), #segStart and segEnd | ||
| warning = function(w) rep(NA, 2)) | ||
| } | ||
| } | ||
| } else if (timewindowi == "WW" || timewindowi == "OO") { | ||
| windowEdge = ifelse(timewindowi == "WW", yes = -1, no = 1) | ||
| if (wi <= (Nwindows - 1)) { # all full windows | ||
|
|
@@ -131,15 +76,87 @@ g.part5.definedays = function(nightsi, wi, indjump, epochSize, qqq_backup = c(), | |
| # not informative. | ||
| qqq = c(NA, NA) | ||
| } | ||
| # build up segments | ||
| if (!is.na(qqq[1]) & !is.na(qqq[2])) { | ||
| segments = list(qqq) | ||
| start = format(ts$time[qqq[1]], "%H:%M:%S") | ||
| end = format(ts$time[qqq[2]], "%H:%M:%S") | ||
| names(segments) = paste(start, end, sep = "-") | ||
| segments_names = timewindowi | ||
| if (wi == length(which(diff(ts$diur) == windowEdge)) - 1) { | ||
| lastDay = TRUE | ||
| } | ||
| if (qqq[2] >= Nts - 1) { | ||
| qqq[2] = Nts | ||
| lastDay = TRUE | ||
| } | ||
| } | ||
| qqq_backup = qqq | ||
| # in MM, also define segments of the day based on qwindow | ||
| if (!is.na(qqq[1]) & !is.na(qqq[2])) { | ||
| segments_timing = NULL | ||
| if (qqq[2] > Nts) qqq[2] = Nts | ||
| fullQqq = qqq[1]:qqq[2] | ||
| firstepoch = format(ts$time[qqq[1]], "%H:%M:%S") | ||
| lastepoch = format(ts$time[qqq[2]], "%H:%M:%S") | ||
| qnames = NULL | ||
| if (is.data.frame(qwindow)) { | ||
| date_of_interest = substr(ts$time[qqq[1]], 1, 10) | ||
| qdate = which(qwindow$ID == ID & qwindow$date == date_of_interest) | ||
| if (length(qdate) == 1) { # if ID/date matched with activity log | ||
| qnames = unlist(qwindow$qwindow_names[qdate]) | ||
| qwindow = unlist(qwindow$qwindow_values[qdate]) | ||
| qwindow_order = order(qwindow) | ||
| qwindow = qwindow[qwindow_order] | ||
| qnames = qnames[qwindow_order] | ||
| } else { # if ID/date not correctly matched with activity log | ||
| qwindow = c(0, 24) | ||
| } | ||
| } else { | ||
| qwindow = sort(qwindow) | ||
| if (qwindow[1] != 0) qwindow = c(0, qwindow) | ||
| if (qwindow[length(qwindow)] != 24) qwindow = c(qwindow, 24) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My preliminary asumption was that segmentation of
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Day segment definitions are still based on timeslot defined between midnight and midnight. None of the day segment analysis functionality in GGIR facilitates time segments that cross midnight. To facilitate that we would have to completely revise how daysegment analysis is done everywhere in GGIR, but that was not the goal for the project I did. What we have had so far are MM day segments that do not care whether a segment is part of the present, previous or next sleep-window cycle. What this PR adds is OO and WW day segments that make sure that only time points from the present sleep-wake or wake-sleep cycle are included. For example, when a person sleeps from 1:00 to 7:00 and the first window of the day is defined as 0:00-8:00. In the MM approach this would result in activity before and after sleep being combined into one segment. For some research questions this is problematic, they much rather have activity before 1:00 count towards the day that precedes sleep and activity between 7:00 and 8:00 count towards the day that succeeds sleep. Which approach is best depends on the research question. I will revise documentation to clarify this. |
||
| } | ||
| # define segments timing in H:M:S format | ||
| breaks = qwindow2timestamp(qwindow, epochSize) | ||
| startOfSegments = breaks[-length(breaks)] | ||
| endOfSegments = subtractEpochFromTimeName(breaks[-1], epochSize) | ||
| if (length(startOfSegments) > 1) { # when qwindow segments are defined, add fullwindow at the beginning | ||
| startOfSegments = c(firstepoch, startOfSegments) | ||
| endOfSegments = c(lastepoch, endOfSegments) | ||
| } | ||
| segments_timing = paste(startOfSegments, endOfSegments, sep = "-") | ||
| # define segment names based on qnames or segmentX | ||
| if (is.null(qnames)) { | ||
| segments_names = paste0(paste0(timewindowi, "segment"), 0:(length(segments_timing) - 1)) | ||
| segments_names = gsub(paste0(timewindowi, "segment0"), timewindowi, segments_names) | ||
| } else { | ||
| segments_names = c(timewindowi, paste(paste0(timewindowi, "segment"), | ||
| qnames[-length(qnames)], qnames[-1], sep = "-")) | ||
| } | ||
| # Get indices in ts for segments start and end limits | ||
| hms = format(ts$time[fullQqq], format = "%H:%M:%S") | ||
| segments = vector("list", length = length(segments_timing)) | ||
| names(segments) = segments_timing | ||
| for (si in 1:length(segments_timing)) { | ||
| s0s1 = unlist(strsplit(segments_timing[si], split = "[-]")) | ||
| s0s1 = format(s0s1, format = "%H:%M:%S") | ||
| # tryCatch is needed in the case that the segment is not available in ts, | ||
| # then a no non-missing values warning would be triggered by the which function | ||
| if (si == 1) { | ||
| test_seg_condition = NULL | ||
| segments[[si]] = range(fullQqq) | ||
| } else { | ||
| test_seg_condition = which(hms >= s0s1[1] & hms <= s0s1[2]) | ||
| if (any(diff(test_seg_condition) > 1) & segments_names[si] %in% c("WW", "OO") == FALSE) { | ||
| # window is more than 24 hours and segment occurs twice | ||
| # we keep both index ranges | ||
| jump = which(diff(test_seg_condition) > 1) | ||
| test_seg_condition1 = test_seg_condition[1:jump] | ||
| test_seg_condition2 = test_seg_condition[(jump + 1):length(test_seg_condition)] | ||
| segments[[si]] = c(tryCatch(range(fullQqq[test_seg_condition1]), #segStart and segEnd | ||
| warning = function(w) rep(NA, 2)), | ||
| tryCatch(range(fullQqq[test_seg_condition2]), #segStart and segEnd | ||
| warning = function(w) rep(NA, 2))) | ||
| } else { | ||
| segments[[si]] = tryCatch(range(fullQqq[test_seg_condition]), #segStart and segEnd | ||
| warning = function(w) rep(NA, 2)) | ||
| } | ||
| } | ||
| } | ||
| if (wi >= Nwindows) lastDay = TRUE | ||
| } | ||
| return(invisible(list(qqq = qqq, qqq_backup = qqq_backup, lastDay = lastDay, | ||
| segments = segments, segments_names = segments_names))) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.