diff --git a/.Rbuildignore b/.Rbuildignore index 4f32cef62..e3986b988 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -19,4 +19,5 @@ RELEASE_CYCLE.md codecov.yml index.md ^inst/doc/*.html -^vignettes/HouseHoldCoanalysis.Rmd \ No newline at end of file +^vignettes/HouseHoldCoanalysis.Rmd +^vignettes/Cookbook.Rmd \ No newline at end of file diff --git a/NEWS.md b/NEWS.md index 11670290a..29e399db4 100644 --- a/NEWS.md +++ b/NEWS.md @@ -4,6 +4,10 @@ - Report part 5: fix bug that was introduced on 2024-Feb-19 in the calculation of wear percentage #1148 +- Part 3 and 4: Revise NotWorn algorithm to work with both count and raw data with varying degrees of nonwear. Further, when HASPT.algo is set to NotWorn then a second guider can optionally be specified in case the accelerometer unexpectedly worn by the participant. #1089 + +- Visualreport: Improve handling of recordings where the accelerometer was not worn. + - Part 1: Enable timegap imputation for ad-hoc csv data. #1154 - Part 1: Reduce constraints on value for parameter chunksize #1155. @@ -14,6 +18,8 @@ - Vignette: Migrated many sections from main CRAN vignette to wadpac.github.io/GGIR/ +- Part 3: Fix handling of recordings with only 1 midnight that start before 4am, #1160 + # CHANGES IN GGIR VERSION 3.1-1 - Part 2: Corrected calculation of LXhr and MXhr which had one hour offset when timing was after midnight, #1117 diff --git a/R/GGIR.R b/R/GGIR.R index d2df87c17..cd8c98deb 100644 --- a/R/GGIR.R +++ b/R/GGIR.R @@ -335,7 +335,7 @@ GGIR = function(mode = 1:5, datadir = c(), outputdir = c(), "GGIRversion", "dupArgValues", "verbose", "is_GGIRread_installed", "is_read.gt3x_installed", "is_ActCR_installed", "is_actilifecounts_installed", "rawaccfiles", "is_readxl_installed", - "checkFormat", "getExt") == FALSE)] + "checkFormat", "getExt", "rawaccfiles_formats") == FALSE)] config.parameters = mget(LS) config.matrix = as.data.frame(createConfigFile(config.parameters, GGIRversion)) diff --git a/R/HASIB.R b/R/HASIB.R index ac7558474..e995e8de8 100644 --- a/R/HASIB.R +++ b/R/HASIB.R @@ -223,8 +223,17 @@ HASIB = function(HASIB.algo = "vanHees2015", timethreshold = c(), anglethreshold # around to avoid having to completely redesign GGIR just for those studies. sib_classification = as.data.frame(matrix(0, Nvalues, 1)) - activityThreshold = as.numeric(quantile(x = activity, probs = 0.1) * 2) - activity2 = zoo::rollmax(x = activity, k = 3600 / epochsize, fill = 1) + activity2 = zoo::rollmax(x = activity, k = 300 / epochsize, fill = 1) + # ignore zeros because in ActiGraph with many zeros it skews the distribution + nonzero = which(activity2 != 0) + if (length(nonzero) > 0) { + activityThreshold = sd(activity2[nonzero], na.rm = TRUE) * 0.05 + if (activityThreshold < min(activity)) { + activityThreshold = quantile(activity2[nonzero], probs = 0.1) + } + } else { + activityThreshold = 0 + } zeroMovement = which(activity2 <= activityThreshold) if (length(zeroMovement) > 0) { sib_classification[zeroMovement, 1] = 1 diff --git a/R/HASPT.R b/R/HASPT.R index 89362a50d..6fd651aa0 100644 --- a/R/HASPT.R +++ b/R/HASPT.R @@ -18,7 +18,7 @@ HASPT = function(angle, sptblocksize = 30, spt_max_gap = 60, ws3 = 5, # threshold = 10th percentile (constrained to 0.13-0.5 if required) medabsdi = function(angle) { #50th percentile, do not use mean because that will be outlier sensitive - angvar = stats::median(abs(diff(angle))) + angvar = stats::median(abs(diff(angle))) return(angvar) } k1 = 5 * (60/ws3) @@ -39,7 +39,7 @@ HASPT = function(angle, sptblocksize = 30, spt_max_gap = 60, ws3 = 5, # threshold = 45 degrees x = abs(angle) threshold = 45 - } else if (HASPT.algo == "NotWorn") { + } else if (HASPT.algo == "NotWorn") { # When protocol is to not wear sensor during the night, # and data is collected in count units we do not know angle # as needed for HorAngle and HDCZA. @@ -52,15 +52,20 @@ HASPT = function(angle, sptblocksize = 30, spt_max_gap = 60, ws3 = 5, # smooth x to 5 minute rolling average to reduce sensitivity to sudden peaks ma <- function(x, n = 300 / ws3){stats::filter(x, rep(1 / n, n), sides = 2, circular = TRUE)} x = ma(x) - activityThreshold = sd(x, na.rm = TRUE) * 0.2 - # For sensewear external data this will not work as it mostly has values of 1 and up. - if (activityThreshold < min(activity)) { - activityThreshold = quantile(x, probs = 0.1) + nonzero = which(x != 0) + if (length(nonzero) > 0) { + activityThreshold = sd(x[nonzero], na.rm = TRUE) * 0.05 + # For sensewear external data this will not work as it mostly has values of 1 and up. + if (activityThreshold < min(activity)) { + activityThreshold = quantile(x, probs = 0.1) + } + } else { + activityThreshold = 0 } # this algorithm looked for x <= threshold, now a minimum quantity is added # to the threshold to allow for consistent definition of nomov below # i.e., x < threshold - threshold = activityThreshold + 0.001 + threshold = activityThreshold + 0.001 } # Now define nomov periods with the selected strategy for invalid time nomov = rep(0,length(x)) # no movement @@ -129,8 +134,8 @@ HASPT = function(angle, sptblocksize = 30, spt_max_gap = 60, ws3 = 5, if (SPTE_start == 0) SPTE_start = 1 part3_guider = HASPT.algo if (is.na(HASPT.ignore.invalid)) { - # investigate if invalid time was included in the SPT definition, - # and if so, keep track of that in the guider. This is needed in the + # investigate if invalid time was included in the SPT definition, + # and if so, keep track of that in the guider. This is needed in the # case that sleeplog is used, to inform part 4 that it should # trust the sleeplog times for this specific night. spt_long = rep(0, length(invalid)) @@ -141,6 +146,28 @@ HASPT = function(angle, sptblocksize = 30, spt_max_gap = 60, ws3 = 5, } } + # # Code to help investigate classifications: + # plot(x, col = "black", type = "l") + # abline(v = SPTE_start, col = "green", lwd = 2) + # abline(v = SPTE_end, col = "red", lwd = 2) + # rect(xleft = s1, ybottom = rep(0, length(s1)), + # xright = e1, ytop = rep(0.1, length(s1)), + # col = rgb(0, 0, 255, max = 255, alpha = 50), border = NA) + # + # rect(xleft = s5, ybottom = rep(0.1, length(s1)), + # xright = e5, ytop = rep(1, length(s1)), + # col = rgb(255, 0, 0, max = 255, alpha = 20), border = NA) + # lines(x, col = "black", type = "l") + # abline(h = threshold, col = "purple", lwd = 2) + # inva = which(invalid == 1) + # if (length(inva) > 0) { + # lines(inva, rep(0.1, length(inva)), + # type = "p", pch = 20, lwd = 4, col = "black") + # } + # lines(invalid* 0.05, type = "l", col = "red") + # # graphics.off() + # browser() + } else { SPTE_end = c() SPTE_start = c() diff --git a/R/check_params.R b/R/check_params.R index 315dc7545..9a075a905 100644 --- a/R/check_params.R +++ b/R/check_params.R @@ -176,7 +176,7 @@ check_params = function(params_sleep = c(), params_metrics = c(), if (length(params_sleep) > 0) { if (length(params_sleep[["def.noc.sleep"]]) != 2) { - if (params_sleep[["HASPT.algo"]] %in% c("HorAngle", "NotWorn") == FALSE) { + if (params_sleep[["HASPT.algo"]][1] %in% c("HorAngle", "NotWorn") == FALSE) { params_sleep[["HASPT.algo"]] = "HDCZA" } } else if (length(params_sleep[["def.noc.sleep"]]) == 2) { @@ -200,13 +200,13 @@ check_params = function(params_sleep = c(), params_metrics = c(), if (length(params_general) > 0 & length(params_metrics) > 0 & length(params_sleep) > 0) { if (params_general[["sensor.location"]] == "hip" && - params_sleep[["HASPT.algo"]] %in% c("notused", "NotWorn") == FALSE) { + params_sleep[["HASPT.algo"]][1] %in% c("notused", "NotWorn") == FALSE) { if (params_metrics[["do.anglex"]] == FALSE | params_metrics[["do.angley"]] == FALSE | params_metrics[["do.anglez"]] == FALSE) { warning(paste0("\nWhen working with hip data all three angle metrics are needed,", "so GGIR now auto-sets arguments do.anglex, do.angley, and do.anglez to TRUE."), call. = FALSE) params_metrics[["do.anglex"]] = params_metrics[["do.angley"]] = params_metrics[["do.anglez"]] = TRUE } - if (params_sleep[["HASPT.algo"]] != "HorAngle") { + if (params_sleep[["HASPT.algo"]][1] != "HorAngle") { warning("\nChanging HASPT.algo value to HorAngle, because sensor.location is set as hip", call. = FALSE) params_sleep[["HASPT.algo"]] = "HorAngle"; params_sleep[["def.noc.sleep"]] = 1 } @@ -230,12 +230,12 @@ check_params = function(params_sleep = c(), params_metrics = c(), params_sleep[["def.noc.sleep"]] = 1 } - if (params_sleep[["HASPT.algo"]] == "HorAngle" & params_sleep[["sleepwindowType"]] != "TimeInBed") { + if (params_sleep[["HASPT.algo"]][1] == "HorAngle" & params_sleep[["sleepwindowType"]] != "TimeInBed") { warning("\nHASPT.algo is set to HorAngle, therefore auto-updating sleepwindowType to TimeInBed", call. = FALSE) params_sleep[["sleepwindowType"]] = "TimeInBed" } - if (length(params_sleep[["loglocation"]]) == 0 & params_sleep[["HASPT.algo"]] != "HorAngle" & params_sleep[["sleepwindowType"]] != "SPT") { + if (length(params_sleep[["loglocation"]]) == 0 & params_sleep[["HASPT.algo"]][1] != "HorAngle" & params_sleep[["sleepwindowType"]] != "SPT") { warning("\nAuto-updating sleepwindowType to SPT because no sleeplog used and neither HASPT.algo HorAngle used.", call. = FALSE) params_sleep[["sleepwindowType"]] = "SPT" } @@ -367,7 +367,7 @@ check_params = function(params_sleep = c(), params_metrics = c(), } if (length(params_general) > 0 & length(params_sleep) > 0) { - if (params_sleep[["HASPT.algo"]] == "HorAngle") { + if (params_sleep[["HASPT.algo"]][1] == "HorAngle") { # Not everywhere in the code we check that when HASPT.algo is HorAngle, sensor.location is hip. # However, the underlying assumption is that they are linked. Even if a study would # use a waist or chest worn sensor we refer to it as hip as the orientation and need diff --git a/R/convertEpochData.R b/R/convertEpochData.R index 3323d13ee..0c1f02bf5 100644 --- a/R/convertEpochData.R +++ b/R/convertEpochData.R @@ -522,6 +522,9 @@ convertEpochData = function(datadir = c(), metadatadir = c(), M$metashort = as.data.frame(cbind(time_shortEp_8601, D[1:length(time_shortEp_8601), ])) colnames(M$metashort) = c("timestamp", colnames(D)) + for (ic in 2:ncol(M$metashort)) { + M$metashort[, ic] <- as.numeric(M$metashort[, ic]) + } } if (length(which(is.na(M$metashort$ZCY) == TRUE)) > 0) { # impute missing data by zero diff --git a/R/g.part4.R b/R/g.part4.R index d431deea5..89caf9e72 100644 --- a/R/g.part4.R +++ b/R/g.part4.R @@ -291,7 +291,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, # explicitely asks for it defaultGuiderOnset = SPTE_start[j] defaultGuiderWake = SPTE_end[j] - guider = params_sleep[["HASPT.algo"]] # HDCZA, NotWorn, HorAngle (or plus invalid) + guider = params_sleep[["HASPT.algo"]][1] # HDCZA, NotWorn, HorAngle (or plus invalid) defaultGuider = part3_guider[j] if (is.null(defaultGuider)) defaultGuider = guider #this ensures compatibility with previous versions in which part3_guider was not stored if (is.na(defaultGuiderOnset) == TRUE) { @@ -435,7 +435,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, } # now generate empty overview for this night / person dummyspo = data.frame(nb = numeric(1), start = numeric(1), end = numeric(1), - dur = numeric(1), def = character(1)) + overlapGuider = numeric(1), def = character(1)) dummyspo$nb[1] = 1 spo_day = c() spo_day_exists = FALSE @@ -473,11 +473,11 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, # now get sleep periods nsp = length(unique(sleepdet.t$sib.period)) #number of sleep periods spo = data.frame(nb = numeric(nsp), start = numeric(nsp), end = numeric(nsp), - dur = numeric(nsp), def = character(nsp)) + overlapGuider = numeric(nsp), def = character(nsp)) if (nsp <= 1 & unique(sleepdet.t$sib.period)[1] == 0) { # no sleep periods spo$nb[1] = 1 - spo[1, c("start", "end", "dur")] = 0 + spo[1, c("start", "end", "overlapGuider")] = 0 spo$def[1] = k if (daysleeper[j] == TRUE) { tmpCmd = paste0("spo_day", k, "= c()") @@ -567,7 +567,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, # add empty spo object, in case it was removed above # we do this because code below assumes that spo is a matrix spo = data.frame(nb = numeric(1), start = numeric(1), end = numeric(1), - dur = numeric(1), def = character(1)) + overlapGuider = numeric(1), def = character(1)) spo$nb[1] = 1 spo[1, 2:4] = 0 spo$def[1] = k @@ -584,10 +584,16 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, } # If no SIBs overlap with the guider window if (relyonguider_thisnight == TRUE) { - newlines = rbind(spo[1, ], spo[1, ]) - newlines[1, 1:4] = c(nrow(spo) + 1, GuiderOnset, GuiderOnset + 1/60, 1) - newlines[2, 1:4] = c(nrow(spo) + 1, GuiderWake - 1/60, GuiderWake, 1) - spo = rbind(spo, newlines) + if (guider != "NotWorn") { + newlines = rbind(spo[1, ], spo[1, ]) + newlines[1, 1:4] = c(nrow(spo) + 1, GuiderOnset, GuiderOnset + 1/60, 1) + newlines[2, 1:4] = c(nrow(spo) + 1, GuiderWake - 1/60, GuiderWake, 1) + spo = rbind(spo, newlines) # When NotWorn was used then fully trust on guider and ignore sibs detected + } else { + newlines = spo[1, ] # initialise object + newlines[1, 1:4] = c(nrow(spo) + 1, GuiderOnset, GuiderWake, 1) + spo = newlines + } spo = spo[order(spo$start), ] spo$nb = 1:nrow(spo) relyonguider_thisnight = TRUE @@ -600,10 +606,10 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, if (spo$end[evi] < GuiderWake & spo$start[evi] > GuiderOnset) { # if using a time in bed reference, then sleep can never # start before time in bed - spo$dur[evi] = 1 #All sib that start after guider onset and end before guider wake + spo$overlapGuider[evi] = 1 #All sib that start after guider onset and end before guider wake } } else { - spo$dur[evi] = 1 # All sib that end after guider onset and start before guider wake + spo$overlapGuider[evi] = 1 # All sib that end after guider onset and start before guider wake } if (params_sleep[["relyonguider"]] == TRUE | relyonguider_thisnight == TRUE) { # Redefine sib start and end if it overlaps with guider @@ -623,7 +629,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, # for the labelling above it was needed to have times > 36, but for the plotting # time in the second day needs to be returned to a normal 24 hour scale. reversetime2 = which(spo$start >= 36) - reversetime3 = which(spo$end >= 36) + reversetime3 = which(spo$end >= 36 & spo$end - 24 > spo$start) if (length(reversetime2) > 0) spo$start[reversetime2] = spo$start[reversetime2] - 24 if (length(reversetime3) > 0) spo$end[reversetime3] = spo$end[reversetime3] - 24 } @@ -685,6 +691,18 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, if (length(rowswithdefi) > 0) { # only process day if there are at least 2 sustained inactivity bouts spocum.t = spocum[rowswithdefi, ] + evin = 2 + if (guider == "NotWorn") { + while (evin <= nrow(spocum.t)) { + if (spocum.t$start[evin] - spocum.t$start[evin - 1] < -2) { + spocum.t$start[evin] = spocum.t$start[evin] + 24 + } + if (spocum.t$end[evin] - spocum.t$end[evin - 1] < -2) { + spocum.t$end[evin] = spocum.t$end[evin] + 24 + } + evin = evin + 1 + } + } # in DST it can be that a double hour is not recognized as part of the SPT correct01010pattern = function(x) { x = as.numeric(x) @@ -697,7 +715,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, return(x) } delta_t1 = diff(as.numeric(spocum.t$end)) - spocum.t$dur = correct01010pattern(spocum.t$dur) + spocum.t$overlapGuider = correct01010pattern(spocum.t$overlapGuider) #---------------------------- nightsummary[sumi, 1] = accid @@ -707,8 +725,8 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, #------------------------------------ # ACCELEROMETER - if (length(which(as.numeric(spocum.t$dur) == 1)) > 0) { - rtl = which(spocum.t$dur == 1) + if (length(which(as.numeric(spocum.t$overlapGuider) == 1)) > 0) { + rtl = which(spocum.t$overlapGuider == 1) nightsummary[sumi, 3] = spocum.t$start[rtl[1]] nightsummary[sumi, 4] = spocum.t$end[rtl[length(rtl)]] } else { @@ -774,18 +792,17 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, nightsummary[sumi, 13] = 1 } # Accumulated sustained inactivity bouts during SPT (nocturnal) and dyatime - nocs = as.numeric(spocum.t$end[which(spocum.t$dur == 1)]) - - as.numeric(spocum.t$start[which(spocum.t$dur == 1)]) - sibds = as.numeric(spocum.t$end[which(spocum.t$dur == 0)]) - - as.numeric(spocum.t$start[which(spocum.t$dur == 0)]) + nocs = as.numeric(spocum.t$end[which(spocum.t$overlapGuider == 1)]) - + as.numeric(spocum.t$start[which(spocum.t$overlapGuider == 1)]) + sibds = as.numeric(spocum.t$end[which(spocum.t$overlapGuider == 0)]) - + as.numeric(spocum.t$start[which(spocum.t$overlapGuider == 0)]) # it is possible that nocs is negative if when sleep episode starts before dst # in the autumn and ends inside the dst hour negval = which(nocs < 0) if (length(negval) > 0) { - kk0 = as.numeric(spocum.t$start[which(spocum.t$dur == 1)]) # episode onsets - kk1 = as.numeric(spocum.t$end[which(spocum.t$dur == 1)]) # episode endings - kk1[negval] = kk1[negval] + 1 - nocs = kk1 - kk0 + kk0 = as.numeric(spocum.t$start[negval]) # episode onsets + kk1 = as.numeric(spocum.t$end[negval]) + 1 # episode endings + nocs[negval] = kk1 - kk0 } if (length(nocs) > 0) { spocum.t.dur.noc = sum(nocs) @@ -802,7 +819,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, # if yes, then check whether any of the sleep episodes overlaps dst in spring, # one hour skipped if (dst_night_or_not == 1) { - checkoverlap = spocum.t[which(spocum.t$dur == 1), c("start", "end")] + checkoverlap = spocum.t[which(spocum.t$overlapGuider == 1), c("start", "end")] if (nrow(checkoverlap) > 0) { overlaps = which(checkoverlap[, 1] <= (dsthour + 24) & checkoverlap[, 2] >= (dsthour + 25)) @@ -887,12 +904,12 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, spocum.t.dur_sibd_atleast15min = 0 } - nightsummary[sumi, 14] = spocum.t.dur.noc #total nocturnalsleep /accumulated sleep duration + nightsummary[sumi, 14] = spocum.t.dur.noc #SleepDurationInSpt nightsummary[sumi, 15] = nightsummary[sumi, 5] - spocum.t.dur.noc #WASO nightsummary[sumi, 16] = spocum.t.dur_sibd #total sib (sustained inactivty bout) duration during wakinghours - nightsummary[sumi, 17] = length(which(spocum.t$dur == 1)) #number of nocturnalsleep periods + nightsummary[sumi, 17] = length(which(spocum.t$overlapGuider == 1)) #number of nocturnalsleep periods nightsummary[sumi, 18] = nightsummary[sumi, 17] - 1 #number of awakenings - nightsummary[sumi, 19] = length(which(spocum.t$dur == 0)) #number of sib (sustained inactivty bout) during wakinghours + nightsummary[sumi, 19] = length(which(spocum.t$overlapGuider == 0)) #number of sib (sustained inactivty bout) during wakinghours nightsummary[sumi, 20] = as.numeric(spocum.t.dur_sibd_atleast15min) #total sib (sustained inactivty bout) duration during wakinghours of at least 5 minutes #------------------------------------------------------- # Also report timestamps in non-numeric format: @@ -966,7 +983,7 @@ g.part4 = function(datadir = c(), metadatadir = c(), f0 = f0, f1 = f1, spocum.t[pli, c("start", "end")] = spocum.t[pli, c("end", "start")] } } - if (spocum.t$dur[pli] == 1) { + if (spocum.t$overlapGuider[pli] == 1) { colb = rainbow(length(undef), start = 0.7, end = 1) } else { colb = rainbow(length(undef), start = 0.2, end = 0.4) diff --git a/R/g.part5.addfirstwake.R b/R/g.part5.addfirstwake.R index ac292813c..29f852d4f 100644 --- a/R/g.part5.addfirstwake.R +++ b/R/g.part5.addfirstwake.R @@ -81,9 +81,11 @@ g.part5.addfirstwake = function(ts, summarysleep, nightsi, sleeplog, ID, # We do this to make sure that the day numbering # and merging of the sleep variables is still consistent with # the other recording. - dummywake = max(firstonset - round(Nepochsinhour/12), nightsi[1] + round(Nepochsinhour * 6)) - ts$diur[1:dummywake] = 1 - ts$nonwear[1:firstonset] = 1 + if (!is.na(firstonset)) { + dummywake = max(firstonset - round(Nepochsinhour/12), nightsi[1] + round(Nepochsinhour * 6)) + ts$diur[1:dummywake] = 1 + ts$nonwear[1:firstonset] = 1 + } } } return(ts) diff --git a/R/g.plot5.R b/R/g.plot5.R index 93b22f7b4..be98df2c3 100644 --- a/R/g.plot5.R +++ b/R/g.plot5.R @@ -86,16 +86,18 @@ g.plot5 = function(metadatadir = c(), dofirstpage = FALSE, viewingwindow = 1, fnames_ms1_stripped[sel], " because part 4 output was not available." ) ) - next() + next } - pdf(paste0(metadatadir, "/results/file summary reports/Report_", - fnames_ms1_stripped[sel], ".pdf"), paper = "a4", - width = 0, height = 0) + sib.cla.sum = c() load(paste0(ms3dir,"/",fname_ms3[i])) load(paste0(ms1dir,"/",fname_ms1[sel])) ws3 = M$windowsizes[1] ws2 = M$windowsizes[2] + if (nrow(sib.cla.sum) == 0) next + pdf(paste0(metadatadir, "/results/file summary reports/Report_", + fnames_ms1_stripped[sel], ".pdf"), paper = "a4", + width = 0, height = 0) # P2daysummary_tmp = P2daysummary[which(P2daysummary$filename == fnames_ms1_stripped[sel]),] # note that the reports are generated from the raw sleep classification (part4) and no attempt is made to clean it up, @@ -116,7 +118,7 @@ g.plot5 = function(metadatadir = c(), dofirstpage = FALSE, viewingwindow = 1, if (includenightcrit > 1) includenightcrit = includenightcrit / 24 d2excludeb = d2exclude = which(P2daysummary_tmp$`N valid hours` < max(c(includedaycrit, threshold_hrs_of_data_per_day))) - n2excludeb = n2exclude = which(summarysleep_tmp$fraction_night_invalid > includenightcrit + n2excludeb = n2exclude = which(summarysleep_tmp$fraction_night_invalid > (1 - includenightcrit) | summarysleep_tmp$SptDuration == 0) if (length(d2exclude) > 0) { @@ -130,8 +132,12 @@ g.plot5 = function(metadatadir = c(), dofirstpage = FALSE, viewingwindow = 1, n2exclude = n2excludeb } # nights missing in sleep summary? - allnights = 1:max(summarysleep_tmp$night) - missingNights = which(allnights %in% summarysleep_tmp$night == FALSE) + if (length(summarysleep_tmp$night) > 0) { + allnights = 1:max(summarysleep_tmp$night) + missingNights = which(allnights %in% summarysleep_tmp$night == FALSE) + } else { + missingNights = NULL + } if (length(missingNights) > 0) { n2exclude = sort(unique(c(n2exclude, missingNights))) } diff --git a/R/g.sib.det.R b/R/g.sib.det.R index b8f599cd1..870605133 100644 --- a/R/g.sib.det.R +++ b/R/g.sib.det.R @@ -195,7 +195,7 @@ g.sib.det = function(M, IMP, I, twd = c(-12, 12), lastmidnight = midnights[length(midnights)] lastmidnighti = midnightsi[length(midnights)] firstmidnight = time[1] - firstmidnighti = 1 + firstmidnighti = midnightsi[1] } else { cut = which(as.numeric(midnightsi) == 0) if (length(cut) > 0) { @@ -230,11 +230,21 @@ g.sib.det = function(M, IMP, I, twd = c(-12, 12), qqq1 = midnightsi[j] + (twd[1] * (3600 / ws3)) #preceding noon qqq2 = midnightsi[j] + (twd[2] * (3600 / ws3)) #next noon } + if (qqq2 - qqq1 < 60) next # skip night if it has less than 60 epochs sptei = sptei + 1 if (qqq2 > length(time)) qqq2 = length(time) if (qqq1 < 1) qqq1 = 1 night[qqq1:qqq2] = sptei detection.failed = FALSE + # Calculate nonwear percentage for this window + nonwear_percentage = (length(which(invalid[qqq1:qqq2] == 1)) / (qqq2 - qqq1 + 1)) * 100 + guider_to_use = 1 + if (params_sleep[["HASPT.algo"]][1] == "NotWorn" && + nonwear_percentage < 25 && + length(params_sleep[["HASPT.algo"]]) == 2) { + # Nonwear percentage was low, so use alternative guider specified as second element + guider_to_use = 2 + } #------------------------------------------------------------------ # calculate L5 because this is used as back-up approach tmpACC = ACC[qqq1:qqq2] @@ -257,8 +267,8 @@ g.sib.det = function(M, IMP, I, twd = c(-12, 12), tmpANGLE = anglez[qqq1:qqq2] tmpTIME = time[qqq1:qqq2] daysleep_offset = 0 - if (do.HASPT.hip == TRUE & params_sleep[["HASPT.algo"]] != "NotWorn") { - params_sleep[["HASPT.algo"]] = "HorAngle" + if (do.HASPT.hip == TRUE & params_sleep[["HASPT.algo"]][1] != "NotWorn") { + params_sleep[["HASPT.algo"]][1] = "HorAngle" if (params_sleep[["longitudinal_axis"]] == 1) { tmpANGLE = anglex[qqq1:qqq2] } else if (params_sleep[["longitudinal_axis"]] == 2) { @@ -268,7 +278,7 @@ g.sib.det = function(M, IMP, I, twd = c(-12, 12), if (length(params_sleep[["def.noc.sleep"]]) == 1) { spt_estimate = HASPT(angle = tmpANGLE, ws3 = ws3, sptblocksize = sptblocksize, spt_max_gap = spt_max_gap, - HASPT.algo = params_sleep[["HASPT.algo"]], + HASPT.algo = params_sleep[["HASPT.algo"]][guider_to_use], invalid = invalid[qqq1:qqq2], # load only invalid time in the night of interest (i.e., qqq1:qqq2) HDCZA_threshold = params_sleep[["HDCZA_threshold"]], HASPT.ignore.invalid = params_sleep[["HASPT.ignore.invalid"]], @@ -286,7 +296,7 @@ g.sib.det = function(M, IMP, I, twd = c(-12, 12), if (newqqq2 > length(anglez)) newqqq2 = length(anglez) # only try to extract SPT again if it is possible to extract a window of more than 23 hour if (newqqq2 < length(anglez) & (newqqq2 - newqqq1) > (23*(3600/ws3)) ) { - if (do.HASPT.hip == TRUE & params_sleep[["HASPT.algo"]] != "NotWorn") { + if (do.HASPT.hip == TRUE & params_sleep[["HASPT.algo"]][1] != "NotWorn") { tmpANGLE = anglez[newqqq1:newqqq2] if (params_sleep[["longitudinal_axis"]] == 1) { tmpANGLE = anglex[newqqq1:newqqq2] @@ -295,9 +305,10 @@ g.sib.det = function(M, IMP, I, twd = c(-12, 12), } } spt_estimate_tmp = HASPT(angle = tmpANGLE, ws3 = ws3, - sptblocksize = sptblocksize, - spt_max_gap = spt_max_gap, - HASPT.algo = params_sleep[["HASPT.algo"]], invalid = invalid[newqqq1:newqqq2], + sptblocksize = sptblocksize, spt_max_gap = spt_max_gap, + HASPT.algo = params_sleep[["HASPT.algo"]][1], + invalid = invalid[newqqq1:newqqq2], + HDCZA_threshold = params_sleep[["HDCZA_threshold"]], HASPT.ignore.invalid = params_sleep[["HASPT.ignore.invalid"]], activity = ACC[newqqq1:newqqq2]) if (length(spt_estimate_tmp$SPTE_start) > 0) { diff --git a/_pkgdown.yml b/_pkgdown.yml index a57f335f5..3fb795c1d 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -84,6 +84,8 @@ navbar: href: articles/TutorialDaySegmentAnalyses.html - text: Household co-analysis href: articles/HouseHoldCoanalysis.html + - text: Cookbook + href: articles/Cookbook.html structure: left: [chapters, annexes, installation, intro, news, contributing, help] right: [search, github, twitter] diff --git a/docs/404.html b/docs/404.html index 30121e02d..4c39ad141 100644 --- a/docs/404.html +++ b/docs/404.html @@ -6,11 +6,11 @@ Page not found (404) • GGIR - - - + + + - + @@ -20,12 +20,12 @@ - Skip to contents + Skip to contents
diff --git a/docs/articles/chapter0_GetStarted.html b/docs/articles/chapter0_GetStarted.html index 8475ebf14..422ad1359 100644 --- a/docs/articles/chapter0_GetStarted.html +++ b/docs/articles/chapter0_GetStarted.html @@ -168,11 +168,11 @@

Run GGIR for the first timeRelated links

diff --git a/docs/articles/chapter0_Support.html b/docs/articles/chapter0_Support.html index d95a18b74..50fe941c8 100644 --- a/docs/articles/chapter0_Support.html +++ b/docs/articles/chapter0_Support.html @@ -137,7 +137,7 @@

GGIR documentation is openly available for users in several places: