@@ -155,6 +155,7 @@ Facet <- ggproto("Facet", NULL,
155
155
panels
156
156
},
157
157
setup_params = function (data , params ) {
158
+ params $ .possible_columns <- unique(unlist(lapply(data , names )))
158
159
params
159
160
},
160
161
setup_data = function (data , params ) {
@@ -417,11 +418,13 @@ is_facets <- function(x) {
417
418
# when evaluating an expression, you want to see any errors. That does
418
419
# mean you can't have background data when faceting by an expression,
419
420
# but that seems like a reasonable tradeoff.
420
- eval_facets <- function (facets , data , env = globalenv() ) {
421
- vars <- compact(lapply(facets , eval_facet , data , env = env ))
421
+ eval_facets <- function (facets , data , possible_columns = NULL ) {
422
+ vars <- compact(lapply(facets , eval_facet , data , possible_columns = possible_columns ))
422
423
new_data_frame(tibble :: as_tibble(vars ))
423
424
}
424
- eval_facet <- function (facet , data , env = emptyenv()) {
425
+ eval_facet <- function (facet , data , possible_columns = NULL ) {
426
+ # Treat the case when `facet` is a quosure of a symbol specifically
427
+ # to issue a friendlier warning
425
428
if (quo_is_symbol(facet )) {
426
429
facet <- as.character(quo_get_expr(facet ))
427
430
@@ -433,7 +436,22 @@ eval_facet <- function(facet, data, env = emptyenv()) {
433
436
return (out )
434
437
}
435
438
436
- eval_tidy(facet , data , env )
439
+ # Key idea: use active bindings so that column names missing in this layer
440
+ # but present in others raise a custom error
441
+ env <- new_environment(data )
442
+ missing_columns <- setdiff(possible_columns , names(data ))
443
+ undefined_error <- function (e ) abort(" " , class = " ggplot2_missing_facet_var" )
444
+ bindings <- rep_named(missing_columns , list (undefined_error ))
445
+ env_bind_active(env , !!! bindings )
446
+
447
+ # Create a data mask and install a data pronoun manually (see ?new_data_mask)
448
+ mask <- new_data_mask(env )
449
+ mask $ .data <- as_data_pronoun(mask )
450
+
451
+ tryCatch(
452
+ eval_tidy(facet , mask ),
453
+ ggplot2_missing_facet_var = function (e ) NULL
454
+ )
437
455
}
438
456
439
457
layout_null <- function () {
@@ -524,10 +542,11 @@ panel_rows <- function(table) {
524
542
# ' @keywords internal
525
543
# ' @export
526
544
combine_vars <- function (data , env = emptyenv(), vars = NULL , drop = TRUE ) {
545
+ possible_columns <- unique(unlist(lapply(data , names )))
527
546
if (length(vars ) == 0 ) return (new_data_frame())
528
547
529
548
# For each layer, compute the facet values
530
- values <- compact(lapply(data , eval_facets , facets = vars , env = env ))
549
+ values <- compact(lapply(data , eval_facets , facets = vars , possible_columns = possible_columns ))
531
550
532
551
# Form the base data.frame which contains all combinations of faceting
533
552
# variables that appear in the data
0 commit comments