Skip to content

Commit 5482939

Browse files
authored
Layers have names (#5967)
* use `%||%` for `na.rm` * simplify special `key_glyph` case * add `name` field to LayerInstance objects * helper for layer names * apply layer names * add tests * add bullet * fallback for direct `layer()` calls
1 parent 6d2ed6d commit 5482939

File tree

4 files changed

+43
-14
lines changed

4 files changed

+43
-14
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# ggplot2 (development version)
22

3+
* Layers can have names (@teunbrand, #4066).
34
* (internal) improvements to `pal_qualitative()` (@teunbrand, #5013)
45
* `coord_radial(clip = "on")` clips to the panel area when the graphics device
56
supports clipping paths (@teunbrand, #5952).

R/layer.R

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,24 +130,16 @@ layer <- function(geom = NULL, stat = NULL,
130130
position <- check_subclass(position, "Position", env = parent.frame(), call = call_env)
131131

132132
# Special case for na.rm parameter needed by all layers
133-
if (is.null(params$na.rm)) {
134-
params$na.rm <- FALSE
135-
}
136-
137-
# Special case for key_glyph parameter which is handed in through
138-
# params since all geoms/stats forward ... to params
139-
if (!is.null(params$key_glyph)) {
140-
key_glyph <- params$key_glyph
141-
params$key_glyph <- NULL # remove to avoid warning about unknown parameter
142-
}
133+
params$na.rm <- params$na.rm %||% FALSE
143134

144135
# Split up params between aesthetics, geom, and stat
145136
params <- rename_aes(params)
146137
aes_params <- params[intersect(names(params), geom$aesthetics())]
147138
geom_params <- params[intersect(names(params), geom$parameters(TRUE))]
148139
stat_params <- params[intersect(names(params), stat$parameters(TRUE))]
149140

150-
all <- c(geom$parameters(TRUE), stat$parameters(TRUE), geom$aesthetics())
141+
ignore <- c("key_glyph", "name")
142+
all <- c(geom$parameters(TRUE), stat$parameters(TRUE), geom$aesthetics(), ignore)
151143

152144
# Take care of plain patterns provided as aesthetic
153145
pattern <- vapply(aes_params, is_pattern, logical(1))
@@ -181,9 +173,9 @@ layer <- function(geom = NULL, stat = NULL,
181173
}
182174

183175
# adjust the legend draw key if requested
184-
geom <- set_draw_key(geom, key_glyph)
176+
geom <- set_draw_key(geom, key_glyph %||% params$key_glyph)
185177

186-
fr_call <- layer_class$constructor %||% frame_call(call_env)
178+
fr_call <- layer_class$constructor %||% frame_call(call_env) %||% current_call()
187179

188180
ggproto("LayerInstance", layer_class,
189181
constructor = fr_call,
@@ -196,7 +188,8 @@ layer <- function(geom = NULL, stat = NULL,
196188
aes_params = aes_params,
197189
position = position,
198190
inherit.aes = inherit.aes,
199-
show.legend = show.legend
191+
show.legend = show.legend,
192+
name = params$name
200193
)
201194
}
202195

R/plot-construction.R

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,25 @@ ggplot_add.by <- function(object, plot, object_name) {
186186

187187
#' @export
188188
ggplot_add.Layer <- function(object, plot, object_name) {
189+
layers_names <- new_layer_names(object, names(plot$layers))
189190
plot$layers <- append(plot$layers, object)
191+
names(plot$layers) <- layers_names
190192
plot
191193
}
194+
195+
new_layer_names <- function(layer, existing) {
196+
new_name <- layer$name
197+
if (is.null(new_name)) {
198+
# Construct a name from the layer's call
199+
new_name <- call_name(layer$constructor)
200+
201+
if (new_name %in% existing) {
202+
names <- c(existing, new_name)
203+
names <- vec_as_names(names, repair = "unique", quiet = TRUE)
204+
new_name <- names[length(names)]
205+
}
206+
}
207+
208+
names <- c(existing, new_name)
209+
vec_as_names(names, repair = "check_unique")
210+
}

tests/testthat/test-layer.R

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ test_that("layer warns for constant aesthetics", {
138138
expect_snapshot_warning(ggplot_build(p))
139139
})
140140

141+
test_that("layer names can be resolved", {
142+
143+
p <- ggplot() + geom_point() + geom_point()
144+
expect_equal(names(p$layers), c("geom_point", "geom_point...2"))
145+
146+
p <- ggplot() + geom_point(name = "foo") + geom_point(name = "bar")
147+
expect_equal(names(p$layers), c("foo", "bar"))
148+
149+
l <- geom_point(name = "foobar")
150+
expect_error(
151+
p + l + l,
152+
"names are duplicated"
153+
)
154+
})
155+
156+
141157
# Data extraction ---------------------------------------------------------
142158

143159
test_that("AsIs data passes unmodified", {

0 commit comments

Comments
 (0)