diff --git a/DESCRIPTION b/DESCRIPTION index 92365d0d..599da379 100755 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -67,8 +67,10 @@ Collate: 'DataSurvival.R' 'DataJoint.R' 'Grid.R' + 'GridEven.R' 'GridFixed.R' 'GridGrouped.R' + 'GridManual.R' 'GridObserved.R' 'constants.R' 'StanModule.R' diff --git a/NAMESPACE b/NAMESPACE index cf2ef095..dbeade23 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,11 +1,15 @@ # Generated by roxygen2: do not edit by hand S3method(as.CmdStanMCMC,JointModelSamples) +S3method(as.QuantityCollapser,GridEven) S3method(as.QuantityCollapser,GridFixed) S3method(as.QuantityCollapser,GridGrouped) +S3method(as.QuantityCollapser,GridManual) S3method(as.QuantityCollapser,GridObserved) +S3method(as.QuantityGenerator,GridEven) S3method(as.QuantityGenerator,GridFixed) S3method(as.QuantityGenerator,GridGrouped) +S3method(as.QuantityGenerator,GridManual) S3method(as.QuantityGenerator,GridObserved) S3method(as.StanModule,JointModel) S3method(as.StanModule,Link) @@ -27,8 +31,10 @@ S3method(as.list,DataJoint) S3method(as.list,DataLongitudinal) S3method(as.list,DataSubject) S3method(as.list,DataSurvival) +S3method(as.list,GridEven) S3method(as.list,GridFixed) S3method(as.list,GridGrouped) +S3method(as.list,GridManual) S3method(as.list,GridObserved) S3method(as.list,Link) S3method(as.list,LinkComponent) @@ -113,8 +119,10 @@ export(DataJoint) export(DataLongitudinal) export(DataSubject) export(DataSurvival) +export(GridEven) export(GridFixed) export(GridGrouped) +export(GridManual) export(GridObserved) export(JointModel) export(Link) diff --git a/R/DataJoint.R b/R/DataJoint.R index 943932fa..ba6c06c3 100755 --- a/R/DataJoint.R +++ b/R/DataJoint.R @@ -188,7 +188,7 @@ subset.DataJoint <- function(x, patients, ...) { dat <- data.frame( time = data[["event_times"]], event = as.numeric(seq_along(data[["event_times"]]) %in% data[["subject_event_index"]]), - patient = names(data[["pt_to_ind"]]) + patient = names(data[["subject_to_index"]]) ) subset_and_add_grouping(dat, patients) } @@ -246,7 +246,7 @@ extract_observed_values <- function(object) { assert_class(object, "DataJoint") data <- as.list(object) x <- data.frame( - subject = names(data$pt_to_ind)[data$subject_tumour_index], + subject = names(data$subject_to_index)[data$subject_tumour_index], time = data$tumour_time, Yob = data$tumour_value ) diff --git a/R/DataSubject.R b/R/DataSubject.R index 3d83df4c..25e61603 100644 --- a/R/DataSubject.R +++ b/R/DataSubject.R @@ -111,7 +111,7 @@ as_stan_list.DataSubject <- function(object, ...) { n_arms = length(unique(df[[vars$arm]])), subject_study_index = as.numeric(df[[vars$study]]), subject_arm_index = as.numeric(df[[vars$arm]]), - pt_to_ind = stats::setNames( + subject_to_index = stats::setNames( seq_len(nlevels(df[[vars$subject]])), levels(df[[vars$subject]]) ) diff --git a/R/Grid.R b/R/Grid.R index fa5abcf9..2aa48a48 100644 --- a/R/Grid.R +++ b/R/Grid.R @@ -7,11 +7,30 @@ #' If `NULL` will default to 201 evenly spaced timepoints between 0 and either the max #' observation time (for [`LongitudinalQuantities`]) or max event time (for [`SurvivalQuantities`]). #' @param groups (`list`)\cr named list of subjects to extract quantities for. See Group Specification. -#' +#' @param spec (`list`)\cr named list of subjects to extract quantities for. The names of each +#' element should be the required subjects with the element itself being a numeric vector of timepoints +#' to generate the quantity at. +#' @param length.out (`numeric`)\cr number of evenly spaced timepoints to generate quantities at. #' @description #' These functions are used to specify which subjects and timepoints should be generated #' when calculating quantities via [`SurvivalQuantities`] and [`LongitudinalQuantities`]. #' +#' @details +#' +#' - `GridFixed()` is used to specify a fixed set of timepoints to generate quantities at for +#' all the specified subjects. +#' +#' - `GridGrouped()` is similar to `GridFixed()` but allows for groupwise averaging +#' (see Group Specification). +#' +#' - `GridObserved()` generates quantities at the observed longitudinal timepoints for each +#' subject. +#' +#' - `GridManual()` allows for individual timepoint specification for each subject. +#' +#' - `GridEven()` generates quantities for each subject at N evenly spaced timepoints +#' between each subjects first and last longitudinal observations. +#' #' @section Group Specification: #' For `GridGrouped()`, `groups` must be a named list of character vectors. Each element of the list #' must be a character vector of the subjects that will form the group where the element name @@ -163,3 +182,37 @@ setValidity( length.QuantityCollapser <- function(x) { length(x@indexes) } + + +#' Expand and Validate Subjects +#' +#' @param subjects (`character`)\cr vector of subjects that should exist in `data` +#' @param data (`DataJoint`)\cr Survival and Longitudinal Data. +#' +#' @description +#' If `subjects` is `NULL` this will return a named list of all subjects in `data`. +#' Else it will return `subjects` as a named list ensuring that all subjects exist in `data`. +#' +#' @keywords internal +subjects_to_list <- function(subjects = NULL, data) { + data_list <- as.list(data) + subjects_exp <- if (is.null(subjects)) { + subs <- as.list(names(data_list$subject_to_index)) + names(subs) <- names(data_list$subject_to_index) + subs + } else { + subs <- as.list(subjects) + names(subs) <- subjects + subs + } + subjects_exp_vec <- unlist(subjects_exp, use.names = FALSE) + assert_that( + identical(subjects_exp_vec, unique(subjects_exp_vec)), + msg = "All subject names must be unique" + ) + assert_that( + all(subjects_exp_vec %in% names(data_list$subject_to_index)), + msg = "Not all subjects exist within the data object" + ) + subjects_exp +} diff --git a/R/GridEven.R b/R/GridEven.R new file mode 100644 index 00000000..24f8b4ec --- /dev/null +++ b/R/GridEven.R @@ -0,0 +1,82 @@ + +#' @include Grid.R +#' @include generics.R +NULL + + +#' @rdname Grid-Dev +.GridEven <- setClass( + "GridEven", + contains = "Grid", + slots = c( + "subjects" = "character", + "length.out" = "numeric" + ) +) + + +#' @rdname Grid-Functions +#' @export +GridEven <- function(subjects = NULL, length.out = 30) { + .GridEven( + subjects = subjects, + length.out = length.out + ) +} + + +setValidity( + "GridEven", + function(object) { + if (length(object@length.out) != 1 || all(object@length.out <= 0)) { + return("The `length.out` argument must be a positive integer") + } + } +) + + +#' @rdname Quant-Dev +#' @export +as.QuantityGenerator.GridEven <- function(object, data, ...) { + assert_class(data, "DataJoint") + data_list <- as.list(data) + subjects <- unlist(as.list(object, data = data), use.names = FALSE) + assert_that( + all(subjects %in% names(data_list$subject_to_index)), + msg = "All subject names must be in the `DataSubject` object" + ) + + spec <- lapply( + subjects, + \(sub) { + subject_index <- data_list$subject_to_index[[sub]] + time_index <- data_list$subject_tumour_index == subject_index + subject_times <- data_list$tumour_time[time_index] + seq(min(subject_times), max(subject_times), length.out = object@length.out) + } + ) + names(spec) <- subjects + + as.QuantityGenerator( + GridManual(spec), + data = data + ) +} + + +#' @rdname Quant-Dev +#' @export +as.QuantityCollapser.GridEven <- function(object, data, ...) { + generator <- as.QuantityGenerator(object, data) + QuantityCollapser( + times = generator@times, + groups = generator@subjects, + indexes = as.list(seq_along(generator@times)) + ) +} + + +#' @export +as.list.GridEven <- function(x, data, ...) { + subjects_to_list(x@subjects, data) +} diff --git a/R/GridFixed.R b/R/GridFixed.R index 6dc1bd85..b7f21c0a 100644 --- a/R/GridFixed.R +++ b/R/GridFixed.R @@ -56,21 +56,5 @@ as.QuantityCollapser.GridFixed <- function(object, data, ...) { #' @export as.list.GridFixed <- function(x, data, ...) { - data_list <- as.list(data) - subjects <- if (is.null(x@subjects)) { - subs <- as.list(names(data_list$pt_to_ind)) - names(subs) <- names(data_list$pt_to_ind) - subs - } else { - subs <- as.list(x@subjects) - names(subs) <- x@subjects - subs - } - assert_that( - identical( - unlist(subjects, use.names = FALSE), - unique(unlist(subjects, use.names = FALSE)) - ) - ) - subjects + subjects_to_list(x@subjects, data) } diff --git a/R/GridGrouped.R b/R/GridGrouped.R index 6678bd62..625d44d9 100644 --- a/R/GridGrouped.R +++ b/R/GridGrouped.R @@ -46,7 +46,7 @@ as.QuantityGenerator.GridGrouped <- function(object, data, ...) { data_list <- as.list(data) patients_unique <- unique(unlist(object@groups)) assert_that( - all(patients_unique %in% names(data_list$pt_to_ind)) + all(patients_unique %in% names(data_list$subject_to_index)) ) as.QuantityGenerator( GridFixed( @@ -64,7 +64,7 @@ as.QuantityCollapser.GridGrouped <- function(object, data, ...) { assert_class(data, "DataJoint") data_list <- as.list(data) assert_that( - all(unique(unlist(object@groups)) %in% names(data_list$pt_to_ind)) + all(unique(unlist(object@groups)) %in% names(data_list$subject_to_index)) ) time_grid <- expand_time_grid(object@times, max(data_list[["tumour_time"]])) diff --git a/R/GridManual.R b/R/GridManual.R new file mode 100644 index 00000000..1fa2b6e1 --- /dev/null +++ b/R/GridManual.R @@ -0,0 +1,81 @@ + +#' @include Grid.R +#' @include generics.R +NULL + + +#' @rdname Grid-Dev +.GridManual <- setClass( + "GridManual", + contains = "Grid", + slots = c( + "spec" = "list" + ) +) + + +#' @rdname Grid-Functions +#' @export +GridManual <- function(spec) { + .GridManual( + spec = spec + ) +} + + +setValidity( + "GridManual", + function(object) { + subject_names <- names(object@spec) + subject_names_valid <- subject_names[!is.na(subject_names) & subject_names != ""] + if (length(subject_names_valid) != length(object@spec)) { + return("Each element of `subjects` must be named") + } + for (times in object@spec) { + if (!is.numeric(times)) { + return("Each element of `spec` must be a numeric vector") + } + if (length(times) != length(unique(times))) { + return("Each time vector per subject must be unique") + } + } + return(TRUE) + } +) + + +#' @rdname Quant-Dev +#' @export +as.QuantityGenerator.GridManual <- function(object, data, ...) { + assert_class(data, "DataJoint") + data_list <- as.list(data) + assert_that( + all(names(object@spec) %in% names(data_list$subject_to_index)), + msg = "All subject names must be in the `DataSubject` object" + ) + lens <- vapply(object@spec, length, numeric(1)) + .QuantityGenerator( + times = unlist(object@spec, use.names = FALSE), + subjects = rep(names(object@spec), lens) + ) +} + + +#' @rdname Quant-Dev +#' @export +as.QuantityCollapser.GridManual <- function(object, data, ...) { + generator <- as.QuantityGenerator(object, data) + QuantityCollapser( + times = generator@times, + groups = generator@subjects, + indexes = as.list(seq_along(generator@times)) + ) +} + + +#' @export +as.list.GridManual <- function(x, data, ...) { + subs <- as.list(names(x@spec)) + names(subs) <- names(x@spec) + subs +} diff --git a/R/GridObserved.R b/R/GridObserved.R index be1bad9b..21ffade8 100644 --- a/R/GridObserved.R +++ b/R/GridObserved.R @@ -27,7 +27,7 @@ as.QuantityGenerator.GridObserved <- function(object, data, ...) { data_list <- as.list(data) subjects <- unlist(as.list(object, data = data), use.names = FALSE) unique_visits <- tapply(data_list$tumour_time, data_list$subject_tumour_index, unique) - patient_visits <- unique_visits[data_list$pt_to_ind[subjects]] + patient_visits <- unique_visits[data_list$subject_to_index[subjects]] visit_lengths <- vapply(patient_visits, length, numeric(1)) .QuantityGenerator( times = unlist(patient_visits, use.names = FALSE), @@ -49,21 +49,5 @@ as.QuantityCollapser.GridObserved <- function(object, data, ...) { #' @export as.list.GridObserved <- function(x, data, ...) { - data_list <- as.list(data) - subjects <- if (is.null(x@subjects)) { - subs <- as.list(names(data_list$pt_to_ind)) - names(subs) <- names(data_list$pt_to_ind) - subs - } else { - subs <- as.list(x@subjects) - names(subs) <- x@subjects - subs - } - assert_that( - identical( - unlist(subjects, use.names = FALSE), - unique(unlist(subjects, use.names = FALSE)) - ) - ) - subjects + subjects_to_list(x@subjects, data) } diff --git a/R/JointModelSamples.R b/R/JointModelSamples.R index 75e5f58e..bb0fb28c 100644 --- a/R/JointModelSamples.R +++ b/R/JointModelSamples.R @@ -46,7 +46,7 @@ generateQuantities.JointModelSamples <- function(object, generator, type, ...) { length(type) == 1, type %in% c("survival", "longitudinal"), length(patients) == length(times), - all(patients %in% names(data$pt_to_ind)) + all(patients %in% names(data$subject_to_index)) ) if (type == "survival") { @@ -58,7 +58,7 @@ generateQuantities.JointModelSamples <- function(object, generator, type, ...) { } data[["gq_n_quant"]] <- length(patients) - data[["gq_pt_index"]] <- data$pt_to_ind[as.character(patients)] + data[["gq_pt_index"]] <- data$subject_to_index[as.character(patients)] data[["gq_times"]] <- times stanObject <- object@model@stan diff --git a/inst/WORDLIST b/inst/WORDLIST index dfb3f543..8790762f 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -137,3 +137,4 @@ SimLongitudinal SimSurvival geq LLoQ +groupwise diff --git a/man/Grid-Dev.Rd b/man/Grid-Dev.Rd index ef009e10..aa5c69b6 100644 --- a/man/Grid-Dev.Rd +++ b/man/Grid-Dev.Rd @@ -1,15 +1,19 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Grid.R, R/GridFixed.R, R/GridGrouped.R, -% R/GridObserved.R +% Please edit documentation in R/Grid.R, R/GridEven.R, R/GridFixed.R, +% R/GridGrouped.R, R/GridManual.R, R/GridObserved.R \docType{class} \name{Grid-Dev} \alias{Grid-Dev} \alias{Grid-class} \alias{.Grid} +\alias{GridEven-class} +\alias{.GridEven} \alias{GridFixed-class} \alias{.GridFixed} \alias{GridGrouped-class} \alias{.GridGrouped} +\alias{GridManual-class} +\alias{.GridManual} \alias{GridObserved-class} \alias{.GridObserved} \title{Grid Developer Notes} diff --git a/man/Grid-Functions.Rd b/man/Grid-Functions.Rd index 0f4e97b5..a89d1371 100644 --- a/man/Grid-Functions.Rd +++ b/man/Grid-Functions.Rd @@ -1,33 +1,58 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/Grid.R, R/GridFixed.R, R/GridGrouped.R, -% R/GridObserved.R +% Please edit documentation in R/Grid.R, R/GridEven.R, R/GridFixed.R, +% R/GridGrouped.R, R/GridManual.R, R/GridObserved.R \name{Grid-Functions} \alias{Grid-Functions} +\alias{GridEven} \alias{GridFixed} \alias{GridGrouped} +\alias{GridManual} \alias{GridObserved} \title{Quantity Grid Specification} \usage{ +GridEven(subjects = NULL, length.out = 30) + GridFixed(subjects = NULL, times = NULL) GridGrouped(groups, times = NULL) +GridManual(spec) + GridObserved(subjects = NULL) } \arguments{ \item{subjects}{(\code{character} or \code{NULL})\cr vector of subjects to extract quantities for. If \code{NULL} will default to all subjects within the dataset.} +\item{length.out}{(\code{numeric})\cr number of evenly spaced timepoints to generate quantities at.} + \item{times}{(\code{numeric} or \code{NULL})\cr vector of time points to extract quantities at. If \code{NULL} will default to 201 evenly spaced timepoints between 0 and either the max observation time (for \code{\link{LongitudinalQuantities}}) or max event time (for \code{\link{SurvivalQuantities}}).} \item{groups}{(\code{list})\cr named list of subjects to extract quantities for. See Group Specification.} + +\item{spec}{(\code{list})\cr named list of subjects to extract quantities for. The names of each +element should be the required subjects with the element itself being a numeric vector of timepoints +to generate the quantity at.} } \description{ These functions are used to specify which subjects and timepoints should be generated when calculating quantities via \code{\link{SurvivalQuantities}} and \code{\link{LongitudinalQuantities}}. } +\details{ +\itemize{ +\item \code{GridFixed()} is used to specify a fixed set of timepoints to generate quantities at for +all the specified subjects. +\item \code{GridGrouped()} is similar to \code{GridFixed()} but allows for groupwise averaging +(see Group Specification). +\item \code{GridObserved()} generates quantities at the observed longitudinal timepoints for each +subject. +\item \code{GridManual()} allows for individual timepoint specification for each subject. +\item \code{GridEven()} generates quantities for each subject at N evenly spaced timepoints +between each subjects first and last longitudinal observations. +} +} \section{Group Specification}{ For \code{GridGrouped()}, \code{groups} must be a named list of character vectors. Each element of the list diff --git a/man/Quant-Dev.Rd b/man/Quant-Dev.Rd index 5a30c1ce..3c3e493b 100644 --- a/man/Quant-Dev.Rd +++ b/man/Quant-Dev.Rd @@ -1,6 +1,6 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/generics.R, R/Grid.R, R/GridFixed.R, -% R/GridGrouped.R, R/GridObserved.R +% Please edit documentation in R/generics.R, R/Grid.R, R/GridEven.R, +% R/GridFixed.R, R/GridGrouped.R, R/GridManual.R, R/GridObserved.R \docType{class} \name{as.QuantityGenerator} \alias{as.QuantityGenerator} @@ -12,10 +12,14 @@ \alias{QuantityCollapser-class} \alias{.QuantityCollapser} \alias{QuantityCollapser} +\alias{as.QuantityGenerator.GridEven} +\alias{as.QuantityCollapser.GridEven} \alias{as.QuantityGenerator.GridFixed} \alias{as.QuantityCollapser.GridFixed} \alias{as.QuantityGenerator.GridGrouped} \alias{as.QuantityCollapser.GridGrouped} +\alias{as.QuantityGenerator.GridManual} +\alias{as.QuantityCollapser.GridManual} \alias{as.QuantityGenerator.GridObserved} \alias{as.QuantityCollapser.GridObserved} \title{Quantity Developer Notes} @@ -28,6 +32,10 @@ QuantityGenerator(times, subjects) QuantityCollapser(times, groups, indexes) +\method{as.QuantityGenerator}{GridEven}(object, data, ...) + +\method{as.QuantityCollapser}{GridEven}(object, data, ...) + \method{as.QuantityGenerator}{GridFixed}(object, data, ...) \method{as.QuantityCollapser}{GridFixed}(object, data, ...) @@ -36,6 +44,10 @@ QuantityCollapser(times, groups, indexes) \method{as.QuantityCollapser}{GridGrouped}(object, data, ...) +\method{as.QuantityGenerator}{GridManual}(object, data, ...) + +\method{as.QuantityCollapser}{GridManual}(object, data, ...) + \method{as.QuantityGenerator}{GridObserved}(object, data, ...) \method{as.QuantityCollapser}{GridObserved}(object, data, ...) diff --git a/tests/testthat/test-DataJoint.R b/tests/testthat/test-DataJoint.R index 8312d87d..d53b1fdc 100644 --- a/tests/testthat/test-DataJoint.R +++ b/tests/testthat/test-DataJoint.R @@ -38,7 +38,7 @@ test_that("DataJoint basic usage", { li <- as.list(d_joint) expect_equal(li$n_subjects, 3) expect_equal(li$n_tumour_all, 6) - expect_equal(li$pt_to_ind, c("C" = 1, "B" = 2, "A" = 3)) + expect_equal(li$subject_to_index, c("C" = 1, "B" = 2, "A" = 3)) expect_equal(li$n_arms, 3) expect_equal(li$subject_study_index, c(2, 1, 1)) expect_equal(li$n_studies, 2) diff --git a/tests/testthat/test-DataSubject.R b/tests/testthat/test-DataSubject.R index 6b0f9413..807eb62b 100644 --- a/tests/testthat/test-DataSubject.R +++ b/tests/testthat/test-DataSubject.R @@ -20,7 +20,7 @@ test_that("DataSubject works as expected", { expected_variables <- c( "n_subjects", "n_studies", "n_arms", "subject_study_index", - "subject_arm_index", "pt_to_ind" + "subject_arm_index", "subject_to_index" ) li <- as_stan_list(obj) @@ -32,7 +32,7 @@ test_that("DataSubject works as expected", { expect_equal(li$n_arms, 3) expect_equal(li$subject_study_index, c(2, 1, 1, 2)) expect_equal(li$subject_arm_index, c(3, 2, 1, 3)) - expect_equal(li$pt_to_ind, c("C" = 1, "B" = 2, "A" = 3, "D" = 4)) + expect_equal(li$subject_to_index, c("C" = 1, "B" = 2, "A" = 3, "D" = 4)) }) test_that("DataSubject print method works as expected", { diff --git a/tests/testthat/test-Grid.R b/tests/testthat/test-Grid.R index 61740b6b..370aa236 100644 --- a/tests/testthat/test-Grid.R +++ b/tests/testthat/test-Grid.R @@ -105,6 +105,59 @@ test_that("Grid objects work with QuantityGenerator and QuantityCollapser", { ) expect_equal(actual, expected) + + # + # GridManual + # + grid <- GridManual( + spec = list( + "B" = c(2, 4), + "A" = c(1, 10, 50), + "C" = 6 + ) + ) + actual <- as.QuantityGenerator(grid, data = dj) + expected <- .QuantityGenerator( + subjects = c("B", "B", "A", "A", "A", "C"), + times = c(2, 4, 1, 10, 50, 6) + ) + expect_equal(actual, expected) + + actual <- as.QuantityCollapser(grid, data = dj) + expected <- .QuantityCollapser( + groups = c("B", "B", "A", "A", "A", "C"), + times = c(2, 4, 1, 10, 50, 6), + indexes = list(1, 2, 3, 4, 5, 6) + ) + expect_equal(actual, expected) + + + + # + # GridEven + # + grid <- GridEven( + subjects = c("D", "A"), + length.out = 4 + ) + actual <- as.QuantityGenerator(grid, data = dj) + expected <- .QuantityGenerator( + subjects = c("D", "D", "D", "D", "A", "A", "A", "A"), + times = c( + seq(1000, 3000, length.out = 4), + seq(1, 3, length.out = 4) + ) + ) + expect_equal(actual, expected) + + actual <- as.QuantityCollapser(grid, data = dj) + expected <- .QuantityCollapser( + groups = expected@subjects, + times = expected@times, + indexes = as.list(seq_along(expected@times)) + ) + expect_equal(actual, expected) + }) @@ -218,14 +271,28 @@ test_that("GridObservered + Constructs correct quantities", { # Longitudinal Data # # - longquant <- LongitudinalQuantities( + longquant_obsv <- LongitudinalQuantities( mp, grid = GridObserved( subjects = c("pt_004", "pt_002", "pt_050") ) ) + actual_obsv <- summary(longquant_obsv) + + + longquant_manual <- LongitudinalQuantities( + mp, + grid = GridManual( + spec = list( + "pt_004" = dat_lm |> dplyr::filter(pt == "pt_004") |> dplyr::arrange(time) |> dplyr::pull(time), + "pt_002" = dat_lm |> dplyr::filter(pt == "pt_002") |> dplyr::arrange(time) |> dplyr::pull(time), + "pt_050" = dat_lm |> dplyr::filter(pt == "pt_050") |> dplyr::arrange(time) |> dplyr::pull(time) + ) + ) + ) + actual_manual <- summary(longquant_manual) - actual <- summary(longquant) + expect_equal(actual_obsv, actual_manual) pred_mat <- as.CmdStanMCMC(mp)$draws("Ypred", format = "draws_matrix") @@ -256,14 +323,11 @@ test_that("GridObservered + Constructs correct quantities", { upper = apply(preds_reduced, 2, quantile, 0.975) ) - expect_gt(cor(actual$median, expected$median), 0.99999999) - expect_gt(cor(actual$lower, expected$lower), 0.99999999) - expect_gt(cor(actual$upper, expected$upper), 0.99999999) - expect_equal(actual$time, expected$time) - expect_equal(actual$group, expected$group) - - - + expect_gt(cor(actual_obsv$median, expected$median), 0.99999999) + expect_gt(cor(actual_obsv$lower, expected$lower), 0.99999999) + expect_gt(cor(actual_obsv$upper, expected$upper), 0.99999999) + expect_equal(actual_obsv$time, expected$time) + expect_equal(actual_obsv$group, expected$group) # # @@ -317,3 +381,38 @@ test_that("GridObservered + Constructs correct quantities", { expect_equal(actual$time, expected$time) expect_equal(actual$group, expected$pt) }) + + +test_that("subjects_to_list works as expected", { + df_subj <- data.frame( + vpt = factor(c("A", "B", "C"), levels = c("C", "B", "A")), + varm = c("A2", "A3", "A4"), + vstudy = c("S1", "S1", "S2") + ) + + d_joint <- DataJoint( + subject = DataSubject( + data = df_subj, + subject = "vpt", + arm = "varm", + study = "vstudy" + ) + ) + + expect_equal( + subjects_to_list(NULL, data = d_joint), + list("C" = "C", "B" = "B", "A" = "A") + ) + expect_equal( + subjects_to_list(c("A", "B"), data = d_joint), + list("A" = "A", "B" = "B") + ) + expect_equal( + subjects_to_list(c("B"), data = d_joint), + list("B" = "B") + ) + expect_error( + subjects_to_list(c("B", "XX"), data = d_joint), + regex = "Not all subjects exist within the data object" + ) +})