Skip to content

Commit 5c24be6

Browse files
authored
ggplot2 compatibility cleanup (#29)
* leverage ggplot2::ggplot_add for more responsible composition
1 parent 5a1cd97 commit 5c24be6

19 files changed

+63
-108
lines changed

DESCRIPTION

+9-10
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
Package: ggpackets
22
Title: Package Plot Layers for Easier Portability and Modularization
3-
Version: 0.2.1.9000
4-
Authors@R:
5-
person("Doug", "Kelkhoff",
6-
email = "[email protected]",
3+
Version: 0.2.1
4+
Authors@R:
5+
person("Doug", "Kelkhoff",
6+
email = "[email protected]",
77
role = c("aut", "cre"))
8-
Description:
8+
Description:
99
Create groups of 'ggplot2' layers that can be easily migrated from one plot
1010
to another, reducing redundant code and improving the ability to format many
1111
plots that draw from the same source 'ggpacket' layers.
@@ -15,9 +15,7 @@ Depends:
1515
Imports:
1616
utils,
1717
methods,
18-
tibble,
19-
rlang,
20-
crayon
18+
rlang
2119
Suggests:
2220
testthat,
2321
dplyr,
@@ -28,8 +26,9 @@ Suggests:
2826
covr
2927
LazyData: true
3028
License: MIT + file LICENSE
31-
RoxygenNote: 7.2.0
29+
RoxygenNote: 7.2.1
3230
Encoding: UTF-8
3331
Roxygen: list(markdown = TRUE)
3432
VignetteBuilder: knitr
35-
URL: https://dgkf.github.io/ggpackets/
33+
URL: https://github.com/dgkf/ggpackets, https://dgkf.github.io/ggpackets/
34+
BugReports: https://github.com/dgkf/ggpackets/issues

NAMESPACE

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Generated by roxygen2: do not edit by hand
22

3-
S3method("+",gg)
43
S3method(format,ggpacket)
4+
S3method(ggplot_add,ggpacket)
55
S3method(print,ggpacket)
66
export("%+%")
77
export(ggpacket)
8-
importFrom(crayon,red)
98
importFrom(ggplot2,aes)
109
importFrom(ggplot2,ggplot)
10+
importFrom(ggplot2,ggplot_add)
1111
importFrom(ggplot2,ggplot_build)
1212
importFrom(ggplot2,standardise_aes_names)
1313
importFrom(ggplot2,waiver)

NEWS.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
# ggpackets (dev)
1+
# ggpackets v0.2.1
22

3+
* handle `+.gg` using recommended `ggplot2::ggplot_add` instead of intercepting
4+
calls (#24, @dgkf)
35

6+
* remove `crayon` package dependency, only used for console output of missing
7+
aesthetics
48

59
# ggpackets v0.2.0
610

R/ggcall.R

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#' Convert an expression into a call as a list of quosure components
2-
#'
2+
#'
33
#' @param x An expression to convert to a ggcall.
44
#' @param which The relative frame offset in which the expression should be
55
#' eventually evaluated.
66
#'
77
#' @importFrom rlang quos enquo quo_get_expr quo_set_env
88
#' @importFrom ggplot2 standardise_aes_names
99
#'
10+
#' @keywords internal
11+
#'
1012
as_gg_call <- function(x, which = -3L) {
1113
xexpr <- eval(bquote(
1214
substitute(.(substitute(x)))),
@@ -20,7 +22,7 @@ as_gg_call <- function(x, which = -3L) {
2022
if (".id" %in% names(xcall)[-1]) {
2123
xids <- rlang::eval_tidy(xcall[[".id"]])
2224
xcall <- xcall[c(1, 1 + which(names(xcall[-1]) != ".id"))]
23-
}
25+
}
2426
xcallname <- infer_ggcall_name(rlang::quo_get_expr(xcall[[1]]))
2527
} else {
2628
xcall <- rlang::quo_set_env(rlang::enquo(xexpr), parent.frame(-which - 1L))
@@ -39,11 +41,13 @@ as_gg_call <- function(x, which = -3L) {
3941

4042

4143
#' Label ggcall with function name if it can be deduced
42-
#'
44+
#'
4345
#' @param expr An expression from which a call name should be inferred.
44-
#'
46+
#'
47+
#' @keywords internal
48+
#'
4549
infer_ggcall_name <- function(expr) {
46-
# TODO: prohibit names ambiguous with gg args with dots
50+
# TODO: prohibit names ambiguous with gg args with dots
4751
# (inherit.aes, na.rm, show.legend, fun.data, label.r)
4852
if (is.name(expr) && grepl("\\w", expr)) as.character(expr)
4953
else "layer"
@@ -52,10 +56,11 @@ infer_ggcall_name <- function(expr) {
5256

5357

5458
#' Convert ggplot geom layers to friendly names
55-
#'
59+
#'
5660
#' @param x A function name from which an id should be inferred.
57-
#'
61+
#'
62+
#' @keywords internal
63+
#'
5864
infer_ggcall_id <- function(x) {
5965
gsub("^(geom|stat)_", "", x)
6066
}
61-

R/ggpacket.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ required_aesthetics.LayerInstance <- function(x) {
403403
}
404404

405405
required_aesthetics.quosures <- function(x) {
406-
aess <- .all_aesthetics
406+
aess <- .all_aesthetics()
407407
names(aess) <- paste0("..", aess, "..")
408408

409409
layer <- tryCatch(rlang::eval_tidy(x[[1]]), error = function(e) NULL)

R/ggpacket_index.R

-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ subset_ggpacket.character <- function(x, i, ...) {
1111
xs <- vapply(x@ggcalls, function(xi) any(i %in% attr(xi, "ids")), logical(1L))
1212
x[xs, ...]
1313
}
14-

R/ggpacket_show.R

+1-2
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,11 @@ format_ggpacket_mapping.NULL <- function(x,
131131
}
132132

133133
#' @importFrom utils capture.output
134-
#' @importFrom crayon red
135134
format_ggpacket_mapping.default <- function(x,
136135
width = getOption("width", 80) * 0.9, missing_aes = character(0L)) {
137136

138137
x[missing_aes] <- " MISSING "
139-
gsub("\" MISSING \"", crayon::red("<missing>"), utils::capture.output(x)[-1])
138+
gsub("\" MISSING \"", "<missing>", utils::capture.output(x)[-1])
140139
}
141140

142141
format_ggpacket_ggcalls <- function(x,

R/ggpackets.R

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#' plots that draw from the same source ggpacket layers.
55
#'
66
#' @examples
7+
#' library(ggplot2)
78
#'
89
#' # Prep a tidy data.frame to plot with
910
#' airquality_long <- rbind(

R/ggplot2_ext.R

+4-29
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,11 @@
1-
#' ggplot2 internal gg addition method
2-
#'
3-
#' @param e1 Addition lhs
4-
#' @param e2 Addition rhs
5-
#'
6-
.plus_gg <- getNamespace("ggplot2")[["+.gg"]]
7-
8-
9-
#' Intercept ggplot2 ggproto plus operator
10-
#'
11-
#' @param e1 An object to add to a ggproto object.
12-
#' @param e2 A ggproto object to add.
13-
#'
14-
#' @return A \code{ggplot2} object or \code{ggpacket}, dependent on whether
15-
#' \code{e1} is a materialized \code{ggproto} object or a \code{ggpacket}.
16-
#'
17-
#' @importFrom methods new
1+
#' @importFrom ggplot2 ggplot_add
182
#' @export
19-
"+.gg" <- function(e1, e2) {
20-
if (inherits(e2, "ggpacket"))
21-
return(gg_plus_ggpacket(e1, e2))
22-
23-
if (!inherits(e1, "ggproto"))
24-
return(.plus_gg(e1, e2))
25-
26-
methods::new(
27-
"ggpacket",
28-
ggpacket_call,
29-
ggcalls = list(as_gg_call(e1), as_gg_call(e2))
30-
)
3+
ggplot_add.ggpacket <- function(object, plot, object_name) {
4+
gg_plus_ggpacket(plot, object)
315
}
326

337

8+
349
#' Lazy handler for ggplot addition
3510
#'
3611
#' @param e1 Addition lhs.

R/utils_aesthetics.R

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#' Extracted .all_aesthetics from internal ggplot2 with hardcoded fallback
2-
.all_aesthetics <- tryCatch({
2+
.all_aesthetics <- function() {
3+
tryCatch({
34
# attempt to stay current with ggplot .all_aesthetics upstream
4-
get('.all_aesthetics', asNamespace('ggplot2'), inherits = FALSE)
5+
get(".all_aesthetics", asNamespace("ggplot2"), inherits = FALSE)
56
}, error = function(e) {
67
# hard coded fallback in case upstream changes private variable name
78
# #est for fallback viability included in testthat tests
@@ -11,6 +12,7 @@
1112
"upper", "vjust", "weight", "width", "x", "xend", "xmax", "xmin",
1213
"xintercept", "y", "yend", "ymax", "ymin", "yintercept", "z")
1314
})
15+
}
1416

1517

1618

@@ -33,7 +35,7 @@ handle_reset_mapping <- function(mapping) {
3335
#' @param envir An environment in which the dot aesthetics should be evaluated.
3436
#'
3537
substitute_ggcall_dot_aes <- function(mapping, ggcall, envir = parent.frame()) {
36-
aess <- .all_aesthetics
38+
aess <- .all_aesthetics()
3739
names(aess) <- ggplot2::standardise_aes_names(aess)
3840

3941
# add in mappings for alternative naming conventions before substitution
@@ -74,4 +76,3 @@ substitute_quote.quosure <- function(q, env = parent.frame()) {
7476
# TODO: handle mixed quosure environments instead of retaining original
7577
rlang::quo_set_expr(q, do.call(substitute, list(rlang::quo_squash(q), env)))
7678
}
77-

R/zzz.R

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
.onLoad <- function(libname, pkgname) {
22
# Some current base functions are used which are not included in older
3-
# versions of R. These are provided through an 'Enhances' pacakge,
4-
# "backports" but this dependency is unnecessary otherwise.
5-
if (package_version(R.Version()) < package_version("3.5") &&
3+
# versions of R. These are provided through an 'Enhances' package,
4+
# "backports" but this dependency is unnecessary otherwise.
5+
if (package_version(R.Version()) < package_version("3.5") &&
66
requireNamespace("backports")) {
77
backports::import(pkgname, "isFALSE")
88
}
9-
}
9+
}

man/as_gg_call.Rd

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/dot-all_aesthetics.Rd

+1-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/dot-plus_gg.Rd

-16
This file was deleted.

man/ggpackets-package.Rd

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/infer_ggcall_id.Rd

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/infer_ggcall_name.Rd

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/plus-.gg.Rd

-20
This file was deleted.

tests/testthat/test-ggpacket-show.R

+11-4
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@ test_that("ggpacket with a bound ggcall layer prints bound ggcall expression", {
6262

6363
test_that("ggpacket lacking required aesthetics indicates aesthetic missing", {
6464
expect_match({
65-
crayon::strip_style(paste(capture.output({
65+
paste(capture.output({
6666
ggpacket() + geom_line()
67-
}), collapse = "\n"))
67+
}), collapse = "\n")
6868
}, c("`x` -> <missing>"))
6969

7070
expect_match({
71-
crayon::strip_style(paste(capture.output({
71+
paste(capture.output({
7272
ggpacket() + geom_line()
73-
}), collapse = "\n"))
73+
}), collapse = "\n")
7474
}, c("`y` -> <missing>"))
7575
})
7676

@@ -88,3 +88,10 @@ test_that("ggpacket including required aesthetics considers internal remappings"
8888
))
8989
})
9090
})
91+
92+
test_that("show(<ggpacket>) behaviors identical to print for command line output", {
93+
expect_identical(
94+
capture.output(show(ggpacket(aes(y = test)) + geom_line(aes(x = ..y..)))),
95+
capture.output(print(ggpacket(aes(y = test)) + geom_line(aes(x = ..y..))))
96+
)
97+
})

0 commit comments

Comments
 (0)