Skip to content

Commit 1ec8866

Browse files
committed
make stat_function() work with empty input data. fixes tidyverse#3983.
1 parent 49aca36 commit 1ec8866

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

R/geom-function.R

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#' geom_function(fun = dnorm, colour = "red")
1919
#'
2020
#' # To plot functions without data, specify range of x-axis
21-
#' base <- ggplot(data.frame(x = c(-5, 5)), aes(x))
21+
#' base <- ggplot() + xlim(-5, 5)
2222
#' base + geom_function(fun = dnorm)
2323
#' base + geom_function(fun = dnorm, args = list(mean = 2, sd = .5))
2424
#'
@@ -45,8 +45,11 @@ geom_function <- function(mapping = NULL, data = NULL, stat = "function",
4545
position = "identity", ..., na.rm = FALSE,
4646
show.legend = NA, inherit.aes = TRUE) {
4747
# Warn if supplied data is going to be overwritten
48-
if (!is.null(data) && identical(stat, "function")) {
49-
warn("`data` is not used by stat_function()")
48+
if (identical(stat, "function")) {
49+
if (!is.null(data)) {
50+
warn("`data` is not used by stat_function()")
51+
}
52+
data <- ensure_nonempty_data
5053
}
5154

5255
layer(

R/stat-function.r

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ stat_function <- function(mapping = NULL, data = NULL,
2929
if (!is.null(data)) {
3030
warn("`data` is not used by stat_function()")
3131
}
32+
data <- ensure_nonempty_data
3233

3334
layer(
3435
data = data,
@@ -57,15 +58,21 @@ StatFunction <- ggproto("StatFunction", Stat,
5758
default_aes = aes(y = after_scale(y)),
5859

5960
compute_group = function(data, scales, fun, xlim = NULL, n = 101, args = list()) {
60-
range <- xlim %||% scales$x$dimension()
61-
xseq <- seq(range[1], range[2], length.out = n)
62-
63-
if (scales$x$is_discrete()) {
61+
if (is.null(scales$x)) {
62+
range <- xlim %||% c(0, 1)
63+
xseq <- seq(range[1], range[2], length.out = n)
6464
x_trans <- xseq
6565
} else {
66-
# For continuous scales, need to back transform from transformed range
67-
# to original values
68-
x_trans <- scales$x$trans$inverse(xseq)
66+
range <- xlim %||% scales$x$dimension()
67+
xseq <- seq(range[1], range[2], length.out = n)
68+
69+
if (scales$x$is_discrete()) {
70+
x_trans <- xseq
71+
} else {
72+
# For continuous scales, need to back transform from transformed range
73+
# to original values
74+
x_trans <- scales$x$trans$inverse(xseq)
75+
}
6976
}
7077

7178
if (is.formula(fun)) fun <- as_function(fun)
@@ -82,3 +89,15 @@ StatFunction <- ggproto("StatFunction", Stat,
8289
))
8390
}
8491
)
92+
93+
# Convenience function used by `stat_function()` and
94+
# `geom_function()` to convert empty input data into
95+
# non-empty input data without touching any non-empty
96+
# input data that may have been provided.
97+
ensure_nonempty_data <- function(data) {
98+
if (empty(data)) {
99+
new_data_frame(list(group = 1), n = 1)
100+
} else {
101+
data
102+
}
103+
}

man/geom_function.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)