Skip to content

Commit 84a3544

Browse files
committed
Port qplot() to tidy eval
1 parent 1f39e13 commit 84a3544

File tree

3 files changed

+40
-30
lines changed

3 files changed

+40
-30
lines changed

R/quick-plot.r

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,24 +62,33 @@
6262
qplot <- function(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
6363
geom = "auto", xlim = c(NA, NA),
6464
ylim = c(NA, NA), log = "", main = NULL,
65-
xlab = deparse(substitute(x)), ylab = deparse(substitute(y)),
65+
xlab = NULL, ylab = NULL,
6666
asp = NA, stat = NULL, position = NULL) {
6767

68-
testthat::skip("qplot")
68+
caller_env <- parent.frame()
6969

7070
if (!missing(stat)) warning("`stat` is deprecated", call. = FALSE)
7171
if (!missing(position)) warning("`position` is deprecated", call. = FALSE)
7272
if (!is.character(geom)) stop("`geom` must be a character vector", call. = FALSE)
7373

74-
argnames <- names(as.list(match.call(expand.dots = FALSE)[-1]))
75-
arguments <- as.list(match.call()[-1])
76-
env <- parent.frame()
74+
exprs <- rlang::enquos(x = x, y = y, ...)
75+
is_missing <- vapply(exprs, rlang::quo_is_missing, logical(1))
76+
is_constant <- vapply(exprs, rlang::quo_is_call, logical(1), name = "I")
7777

78-
aesthetics <- compact(arguments[.all_aesthetics])
79-
aesthetics <- aesthetics[!is.constant(aesthetics)]
80-
aes_names <- names(aesthetics)
81-
aesthetics <- rename_aes(aesthetics)
82-
class(aesthetics) <- "uneval"
78+
mapping <- new_aes(exprs[!is_missing & !is_constant], env = parent.frame())
79+
consts <- exprs[is_constant]
80+
81+
aes_names <- names(mapping)
82+
mapping <- rename_aes(mapping)
83+
84+
85+
xlab <- rlang::quo_name(exprs$x)
86+
# Work around quo_name() bug: https://github.com/r-lib/rlang/issues/430
87+
if (rlang::quo_is_null(exprs$y)) {
88+
ylab <- "NULL"
89+
} else {
90+
ylab <- rlang::quo_name(exprs$y)
91+
}
8392

8493
if (missing(data)) {
8594
# If data not explicitly specified, will be pulled from workspace
@@ -89,7 +98,8 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
8998
facetvars <- all.vars(facets)
9099
facetvars <- facetvars[facetvars != "."]
91100
names(facetvars) <- facetvars
92-
facetsdf <- as.data.frame(mget(facetvars, envir = env))
101+
# FIXME?
102+
facetsdf <- as.data.frame(mget(facetvars, envir = caller_env))
93103
if (nrow(facetsdf)) data <- facetsdf
94104
}
95105

@@ -98,22 +108,22 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
98108
if ("sample" %in% aes_names) {
99109
geom[geom == "auto"] <- "qq"
100110
} else if (missing(y)) {
101-
x <- eval(aesthetics$x, data, env)
111+
x <- rlang::eval_tidy(mapping$x, data, caller_env)
102112
if (is.discrete(x)) {
103113
geom[geom == "auto"] <- "bar"
104114
} else {
105115
geom[geom == "auto"] <- "histogram"
106116
}
107-
if (missing(ylab)) ylab <- "count"
117+
if (is.null(ylab)) ylab <- "count"
108118
} else {
109119
if (missing(x)) {
110-
aesthetics$x <- bquote(seq_along(.(y)), aesthetics)
120+
mapping$x <- rlang::quo(seq_along(!!mapping$y))
111121
}
112122
geom[geom == "auto"] <- "point"
113123
}
114124
}
115125

116-
p <- ggplot(data, aesthetics, environment = env)
126+
p <- ggplot(data, mapping, environment = NULL)
117127

118128
if (is.null(facets)) {
119129
p <- p + facet_null()
@@ -127,12 +137,8 @@ qplot <- function(x, y = NULL, ..., data, facets = NULL, margins = FALSE,
127137

128138
# Add geoms/statistics
129139
for (g in geom) {
130-
# Arguments are unevaluated because some are aesthetics. Need to evaluate
131-
# params - can't do in correct env because that's lost (no lazyeval)
132-
# so do the best we can by evaluating in parent frame.
133-
params <- arguments[setdiff(names(arguments), c(aes_names, argnames))]
134-
params <- lapply(params, eval, parent.frame())
135-
140+
# We reevaluate constants once per geom for historical reasons?
141+
params <- lapply(consts, rlang::eval_tidy)
136142
p <- p + do.call(paste0("geom_", g), params)
137143
}
138144

man/qplot.Rd

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-qplot.r

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,18 @@ test_that("qplot works with variables in data frame and parent env", {
1414
})
1515

1616
test_that("qplot works in non-standard environments", {
17-
env <- new.env(parent = globalenv())
18-
expr <- quote({
17+
p <- local({
1918
`-1-` <- 10
2019
x <- 1:10
2120
qplot(x, breaks = 0:`-1-`)
2221
})
23-
24-
expect_is(eval(expr, env), "ggplot")
25-
22+
expect_is(p, "ggplot")
2623
})
2724

25+
test_that("qplot() evaluates constants in the right place", {
26+
p <- local({
27+
foo <- "d"
28+
qplot(1, 1, colour = I(paste0("re", foo)))
29+
})
30+
expect_identical(layer_data(p)$colour, I("red"))
31+
})

0 commit comments

Comments
 (0)