-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Boilerplate functions #6143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Boilerplate functions #6143
Changes from 7 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
5f067c1
write boilerplate function
teunbrand 32a4a76
adopt boilerplate where possible
teunbrand 3eee99f
write out all non-standard arguments
teunbrand 26f9f8f
automatically fill in parameters
teunbrand 8c8f795
incorporate small checks
teunbrand fa9f6d2
document
teunbrand 075ea86
accept visual snapshots
teunbrand ea57200
Update R/boilerplates.R
teunbrand 6b44f33
Adopt advice from June
teunbrand 6e71e1a
docfix
teunbrand d488de8
Apply suggestions from code review
teunbrand e6db72d
ensure `list2()` can be found
teunbrand 8c33474
rename `boilerplate()` to `make_constructor()`
teunbrand c11c5ed
give body pretty braces
teunbrand 44cf2dc
purge unused parameters in `stat_bin()`
teunbrand cd54bfb
add Stat method for `make_constructor()`
teunbrand 4dd78b5
use the `make_constructor()` for Stats
teunbrand c7abdd7
revert 4dd78b5c for `layer_sf()` stats
teunbrand d1043b0
mechanism to hide internal variables
teunbrand a68e4bb
document
teunbrand 6f452f4
resolve merge conflict
teunbrand 6c95f24
make GeomCol parent of `geom_col()` again for error message purposes
teunbrand 52e66f2
rebalance omissions
teunbrand 295e36c
resolve merge conflict
teunbrand c7aa7fd
include example of `checks` argument
teunbrand 23f4c71
Hide origin/right arguments that are deprecated
teunbrand 453cf6b
avoid arbitrary whitespace changes
teunbrand 9039e10
resolve merge conflict
teunbrand 9ca4353
apply boilerplate to `stat_connect()`
teunbrand 015cdc1
Also boilerplate `stat_manual()`
teunbrand c5f38c5
boilerplate `geom_text()`
teunbrand f7652fe
remove deprecated args
teunbrand 7625aa2
resolve merge conflict
teunbrand 5d79442
resolve merge conflict
teunbrand e0320f6
add news bullet
teunbrand File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#' @include layer.R | ||
#' @include scale-type.R | ||
NULL | ||
|
||
#' Produce boilerplate constructors | ||
#' | ||
#' The `boilerplate()` functions sets up a user-facing constructor for ggproto | ||
#' classes. Currently, `boilerplate()` is implemented for `Geom` classes. | ||
#' | ||
#' @param x An object to setup a constructor for. | ||
#' @param ... Name-value pairs to use as additional arguments in the | ||
#' constructor. For layers, these are passed on to [`layer(params)`][layer()]. | ||
#' @param checks Expressions evaluated before construction of the object. | ||
#' Can be a `{}` block to include multiple expressions. | ||
#' | ||
#' @return A function | ||
#' @export | ||
#' | ||
#' @examples | ||
#' # For testing purposes, a geom that returns grobs | ||
#' GeomTest <- ggproto( | ||
#' "GeomTest", Geom, | ||
#' draw_group = function(..., grob = grid::pointsGrob()) { | ||
#' return(grob) | ||
#' } | ||
#' ) | ||
#' # Creating a constructor | ||
#' geom_test <- boilerplate(GeomTest) | ||
#' | ||
#' # Note that `grob` is automatically an argument to the function | ||
#' names(formals(geom_test)) | ||
#' | ||
#' # Use in a plot | ||
#' set.seed(1234) | ||
#' p <- ggplot(mtcars, aes(disp, mpg)) | ||
#' p + geom_test() | ||
#' p + geom_test(grob = grid::circleGrob()) | ||
boilerplate <- function(x, ...) { | ||
UseMethod("boilerplate") | ||
} | ||
|
||
#' @export | ||
boilerplate.Geom <- function(x, ..., checks, env = caller_env()) { | ||
|
||
# Check that we can independently find the geom | ||
geom <- gsub("^geom_", "", snake_class(x)) | ||
check_subclass(geom, "Geom", env = env) | ||
|
||
# Split additional arguments into required and extra ones | ||
args <- enexprs(...) | ||
fixed_fmls_names <- c("mapping", "data", "stat", "position", "...", | ||
"na.rm", "show.legend", "inherit.aes") | ||
extra_args <- setdiff(names(args), fixed_fmls_names) | ||
if ("geom" %in% extra_args) { | ||
cli::cli_abort("{.arg geom} is a reserved argument.") | ||
} | ||
|
||
# Fill in values for parameters from draw functions | ||
known_params <- | ||
unique(c(names(args), fixed_fmls_names, "flipped_aes", x$aesthetics())) | ||
missing_params <- setdiff(x$parameters(), known_params) | ||
if (length(missing_params) > 0) { | ||
draw_args <- ggproto_formals(x$draw_panel) | ||
if ("..." %in% names(draw_args)) { | ||
draw_args <- ggproto_formals(x$draw_group) | ||
} | ||
params <- intersect(missing_params, names(draw_args)) | ||
extra_args <- c(extra_args, params) | ||
for (param in params) { | ||
if (!identical(draw_args[[param]], quote(expr = ))) { | ||
args[param] <- draw_args[param] | ||
} | ||
} | ||
missing_params <- setdiff(missing_params, names(args)) | ||
if (length(missing_params) > 0) { | ||
cli::cli_warn( | ||
"In {.fn geom_{geom}}: please consider providing default values for: \\ | ||
{missing_params}." | ||
) | ||
} | ||
} | ||
|
||
# Build function formals | ||
fmls <- list2( | ||
mapping = args$mapping, | ||
data = args$data, | ||
stat = args$stat %||% "identity", | ||
position = args$position %||% "identity", | ||
`...` = quote(expr = ), | ||
!!!args[extra_args], | ||
na.rm = args$na.rm %||% FALSE, | ||
show.legend = args$show.legend %||% NA, | ||
inherit.aes = args$inherit.aes %||% TRUE | ||
) | ||
|
||
if (length(extra_args) > 0) { | ||
extra_args <- paste0( | ||
"\n ", extra_args, " = ", extra_args, ",", collapse = "" | ||
) | ||
teunbrand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
body <- paste0(" | ||
layer( | ||
data = data, | ||
mapping = mapping, | ||
stat = stat, | ||
geom = \"", geom, "\", | ||
position = position, | ||
show.legend = show.legend, | ||
inherit.aes = inherit.aes, | ||
params = list2( | ||
na.rm = na.rm,", | ||
extra_args, " | ||
... | ||
) | ||
) | ||
") | ||
body <- str2lang(body) | ||
teunbrand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
checks <- substitute(checks) | ||
if (!missing(checks)) { | ||
if (is_call(checks, "{")) { | ||
checks[[1]] <- NULL | ||
} | ||
body <- inject(quote(`{`(!!!c(checks, body)))) | ||
teunbrand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
teunbrand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
new_function(fmls, body) | ||
teunbrand marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.