diff --git a/DESCRIPTION b/DESCRIPTION index 39077d11..ed5736b0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -9,7 +9,8 @@ Authors@R: c( person("Thom", "Volker", role = "ctb", comment = c(ORCID = "0000-0002-2408-7820")), person("Gerko", "Vink", role = "ctb", comment = c(ORCID = "0000-0001-9767-1924")), person("Pepijn", "Vink", role = "ctb", comment = c(ORCID = "0000-0001-6960-9904")), - person("Jamie", "Wallis", role = "ctb", comment = c(ORCID = "0000-0003-2765-3813")) + person("Jamie", "Wallis", role = "ctb", comment = c(ORCID = "0000-0003-2765-3813")), + person("Kyle", "Lang", role = "ctb", comment = c(ORCID = "0000-0001-5340-7849")) ) Description: Enhance a 'mice' imputation workflow with visualizations for incomplete and/or imputed data. The plotting functions produce @@ -46,4 +47,4 @@ Config/testthat/edition: 3 Copyright: 'ggmice' authors Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.2 diff --git a/NAMESPACE b/NAMESPACE index 5a976a40..d3b3a8ae 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -13,3 +13,5 @@ export(stripplot) export(xyplot) importFrom(magrittr,"%>%") importFrom(rlang,.data) +importFrom(rlang,enexpr) +importFrom(utils,tail) diff --git a/R/plot_trace.R b/R/plot_trace.R index ec8f2580..2a24321c 100644 --- a/R/plot_trace.R +++ b/R/plot_trace.R @@ -3,11 +3,40 @@ #' @param data An object of class [mice::mids]. #' @param vrb String, vector, or unquoted expression with variable name(s), default is "all". #' +#' @details +#' The `vrb` argument is "quoted" via [rlang::enexpr()] and evaluated according +#' to [Tidy Evaluation principles](https://adv-r.hadley.nz/metaprogramming.html). +#' In practice, this technical nuance only affects users when passing an object +#' from the environment (e.g., a vector of variable names) to the `vrb` argument. +#' In such cases, the object must be "unquoted" via the `!!` prefix operator. +#' #' @return An object of class [ggplot2::ggplot]. #' #' @examples #' imp <- mice::mice(mice::nhanes, print = FALSE) +#' +#' ## Plot all imputed variables #' plot_trace(imp) +#' +#' ## Variables can be specified via character vectors comprising their names +#' plot_trace(imp, "bmi") +#' plot_trace(imp, c("bmi", "hyp")) +#' +#' ## Variable names can be unquoted +#' plot_trace(imp, bmi) +#' plot_trace(imp, c(bmi, hyp)) +#' +#' ## When passing the variable names as an object from the environment, the +#' ## object's name must be unqoted via `!!`. +#' vars <- c("bmi", "hyp") +#' plot_trace(imp, vars) |> try() # Error +#' plot_trace(imp, !!vars) # Runs because the 'vrb' argument is unquoted +#' +#' for(v in vars) +#' plot_trace(imp, !!v) |> print() +#' +#' @importFrom utils tail +#' @importFrom rlang enexpr #' @export plot_trace <- function(data, vrb = "all") { verify_data(data, imp = TRUE) @@ -20,14 +49,27 @@ plot_trace <- function(data, vrb = "all") { sm <- sqrt(data$chainVar) # select variable to plot from list of imputed variables - vrb <- substitute(vrb) + vrb <- enexpr(vrb) + if(is.call(vrb)) + vrb <- as.character(vrb) |> tail(-1) + else if(is.symbol(vrb)) + vrb <- as.character(vrb) + varlist <- names(data$imp)[apply(!(is.nan(mn) | is.na(mn)), 1, all)] - if (as.character(vrb)[1] == "all") { + if (length(vrb) == 1 && as.character(vrb) == "all") { vrb <- varlist - } else { - vrb <- names(dplyr::select(data$data, {{vrb}})) + } else if (any(vrb %nin% colnames(data$data))) { + cli::cli_abort( + c( + "x" = "The following variables are not present in 'data':", + " " = paste(setdiff(vrb, colnames(data$data)), collapse = ", "), + "i" = "Did you forget to use `!!` to unqote the object name you passed to the `vrb` argument?", + "i" = "Or maybe you just made a typo?" + ) + ) } + if (any(vrb %nin% varlist)) { cli::cli_inform( c( @@ -89,3 +131,4 @@ plot_trace <- function(data, vrb = "all") { strip.switch.pad.wrap = ggplot2::unit(0, "cm") ) } + diff --git a/man/plot_trace.Rd b/man/plot_trace.Rd index acb4cf34..f0eb9a96 100644 --- a/man/plot_trace.Rd +++ b/man/plot_trace.Rd @@ -17,7 +17,34 @@ An object of class \link[ggplot2:ggplot]{ggplot2::ggplot}. \description{ Plot the trace lines of the imputation algorithm } +\details{ +The \code{vrb} argument is "quoted" via \code{\link[rlang:defusing-advanced]{rlang::enexpr()}} and evaluated according +to \href{https://adv-r.hadley.nz/metaprogramming.html}{Tidy Evaluation principles}. +In practice, this technical nuance only affects users when passing an object +from the environment (e.g., a vector of variable names) to the \code{vrb} argument. +In such cases, the object must be "unquoted" via the \verb{!!} prefix operator. +} \examples{ imp <- mice::mice(mice::nhanes, print = FALSE) + +## Plot all imputed variables plot_trace(imp) + +## Variables can be specified via character vectors comprising their names +plot_trace(imp, "bmi") +plot_trace(imp, c("bmi", "hyp")) + +## Variable names can be unquoted +plot_trace(imp, bmi) +plot_trace(imp, c(bmi, hyp)) + +## When passing the variable names as an object from the environment, the +## object's name must be unqoted via `!!`. +vars <- c("bmi", "hyp") +plot_trace(imp, vars) |> try() # Error +plot_trace(imp, !!vars) # Runs because the 'vrb' argument is unquoted + +for(v in vars) + plot_trace(imp, !!v) |> print() + } diff --git a/tests/testthat/test-plot_trace.R b/tests/testthat/test-plot_trace.R index ff18805d..f047008e 100644 --- a/tests/testthat/test-plot_trace.R +++ b/tests/testthat/test-plot_trace.R @@ -1,6 +1,7 @@ # create test objects dat <- mice::nhanes imp <- mice::mice(dat, printFlag = FALSE) +v <- c("bmi", "hyp") # tests test_that("plot_trace creates ggplot object", { @@ -11,6 +12,8 @@ test_that("plot_trace creates ggplot object", { expect_s3_class(plot_trace(imp, vrb = bmi), "ggplot") expect_s3_class(plot_trace(imp, vrb = c("bmi", "hyp")), "ggplot") expect_s3_class(plot_trace(imp, vrb = c(bmi, hyp)), "ggplot") + expect_s3_class(plot_trace(imp, vrb = !!v), "ggplot") + expect_s3_class(plot_trace(imp, vrb = !!v[1]), "ggplot") }) test_that("plot_trace returns error with incorrect argument(s)", { @@ -18,4 +21,6 @@ test_that("plot_trace returns error with incorrect argument(s)", { expect_error(plot_trace(imp, vrb = "test")) expect_error(plot_trace(imp, vrb = "age")) expect_message(plot_trace(imp, vrb = c("age", "bmi"))) + expect_error(plot_trace(imp, vrb = v)) + expect_error(plot_trace(imp, vrb = v[1])) })