diff --git a/R/facet-layout.r b/R/facet-layout.r index ef312b4a..fa595af9 100644 --- a/R/facet-layout.r +++ b/R/facet-layout.r @@ -93,8 +93,22 @@ layout_base <- function(data, vars = NULL, drop = TRUE) { # Form the base data frame which contains all combinations of facetting # variables that appear in the data - has_all <- unlist(plyr::llply(values, length)) == length(vars) + has_all <- unlist(lapply(values, length)) == length(vars) if (!any(has_all)) { + all_data_vars <- unique(unlist(lapply(data, names))) + missing_vars <- setdiff(names(vars)[names(vars) != "."], all_data_vars) + if (length(missing_vars) > 0) { + stop(sprintf( + "Facet variable%s not found in data: %s\nAvailable columns: %s\nUse string notation like facet_wrap(\"var\") instead of formula notation facet_wrap(. ~ var)", + if (length(missing_vars) > 1) "s" else "", + paste(missing_vars, collapse = ", "), + paste(all_data_vars, collapse = ", ") + )) + } + # Reached when all facet variables exist somewhere in the data, but no + # single layer has all of them together. For example, facet_grid(X ~ Y) + # where layer 1 only has column X and layer 2 only has column Y — neither + # layer alone satisfies all facetting variables, so has_all is FALSE for every layer. stop("At least one layer must contain all variables used for facetting") } diff --git a/R/z_animintHelpers.R b/R/z_animintHelpers.R index 0fa7791a..f178c65b 100644 --- a/R/z_animintHelpers.R +++ b/R/z_animintHelpers.R @@ -1097,4 +1097,4 @@ selectSSandCS <- function(aesthetics_list){ } ## TODO: how to handle showSelected$ignored in prev animint code?? return(aes.list) -} +} \ No newline at end of file diff --git a/tests/testthat/test-renderer-facet-error-messages.R b/tests/testthat/test-renderer-facet-error-messages.R new file mode 100644 index 00000000..79be2d00 --- /dev/null +++ b/tests/testthat/test-renderer-facet-error-messages.R @@ -0,0 +1,34 @@ +acontext("Facet error messages") +test_that("facet_wrap formula with missing variable gives clear error", { + viz <- list( + scatter = ggplot() + + facet_wrap(. ~ NonExistentColumn) + + geom_point(aes(Sepal.Length, Petal.Length), data = iris) + ) + expect_error( + animint2dir(viz, out.dir = tempfile(), open.browser = FALSE), + "Facet variable not found in data: NonExistentColumn\nAvailable columns: Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, Species\nUse string notation like facet_wrap(\"var\") instead of formula notation facet_wrap(. ~ var)", + fixed = TRUE + ) +}) +test_that("facet_grid formula with missing variable gives clear error", { + viz <- list( + scatter = ggplot() + + facet_grid(. ~ MissingVar) + + geom_point(aes(Sepal.Length, Petal.Length), data = iris) + ) + expect_error( + animint2dir(viz, out.dir = tempfile(), open.browser = FALSE), + "Facet variable not found in data: MissingVar\nAvailable columns: Sepal.Length, Sepal.Width, Petal.Length, Petal.Width, Species\nUse string notation like facet_wrap(\"var\") instead of formula notation facet_wrap(. ~ var)", + fixed = TRUE + ) +}) +test_that("facet_wrap string notation works", { + viz <- list( + scatter = ggplot() + + facet_wrap("Species") + + geom_point(aes(Sepal.Length, Petal.Length), data = iris) + ) + info <- animint2dir(viz, out.dir = tempfile(), open.browser = FALSE) + expect_true(file.exists(file.path(info$out.dir, "index.html"))) +})