Skip to content

Commit 07ddd0c

Browse files
authored
Ensure stateless layer instances (#4448)
1 parent 53c1440 commit 07ddd0c

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

NEWS.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
# ggplot2 (development version)
22

3+
* Fix a bug in the layer implementation that introduced a new state after the
4+
first render which could lead to a different look when rendered the second
5+
time (@thomasp85, #4204)
6+
37
* Make sure `label_bquote()` has access to the calling environment when
48
evaluating the labels (@thomasp85, #4141)
5-
9+
610
* Fix bug in `annotate_logticks()` that would cause an error when used together
711
with `coord_flip()` (@thomasp85, #3954)
812

913
* Fix a bug in `guide_bins()` where keys would disappear if the guide was
1014
reversed (@thomasp85, #4210)
11-
15+
1216
* Fix a bug in legend justification where justification was lost of the legend
1317
dimensions exceeded the available size (@thomasp85, #3635)
1418

R/layer.r

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ Layer <- ggproto("Layer", NULL,
169169
geom_params = NULL,
170170
stat = NULL,
171171
stat_params = NULL,
172+
173+
# These two fields carry state throughout rendering but will always be
174+
# calculated before use
175+
computed_geom_params = NULL,
176+
computed_stat_params = NULL,
177+
172178
data = NULL,
173179
aes_params = NULL,
174180
mapping = NULL,
@@ -276,9 +282,9 @@ Layer <- ggproto("Layer", NULL,
276282
if (empty(data))
277283
return(new_data_frame())
278284

279-
params <- self$stat$setup_params(data, self$stat_params)
280-
data <- self$stat$setup_data(data, params)
281-
self$stat$compute_layer(data, params, layout)
285+
self$computed_stat_params <- self$stat$setup_params(data, self$stat_params)
286+
data <- self$stat$setup_data(data, self$computed_stat_params)
287+
self$stat$compute_layer(data, self$computed_stat_params, layout)
282288
},
283289

284290
map_statistic = function(self, data, plot) {
@@ -339,8 +345,8 @@ Layer <- ggproto("Layer", NULL,
339345
c(names(data), names(self$aes_params)),
340346
snake_class(self$geom)
341347
)
342-
self$geom_params <- self$geom$setup_params(data, c(self$geom_params, self$aes_params))
343-
self$geom$setup_data(data, self$geom_params)
348+
self$computed_geom_params <- self$geom$setup_params(data, c(self$geom_params, self$aes_params))
349+
self$geom$setup_data(data, self$computed_geom_params)
344350
},
345351

346352
compute_position = function(self, data, layout) {
@@ -363,7 +369,7 @@ Layer <- ggproto("Layer", NULL,
363369
},
364370

365371
finish_statistics = function(self, data) {
366-
self$stat$finish_layer(data, self$stat_params)
372+
self$stat$finish_layer(data, self$computed_stat_params)
367373
},
368374

369375
draw_geom = function(self, data, layout) {
@@ -372,8 +378,8 @@ Layer <- ggproto("Layer", NULL,
372378
return(rep(list(zeroGrob()), n))
373379
}
374380

375-
data <- self$geom$handle_na(data, self$geom_params)
376-
self$geom$draw_layer(data, self$geom_params, layout, layout$coord)
381+
data <- self$geom$handle_na(data, self$computed_geom_params)
382+
self$geom$draw_layer(data, self$computed_geom_params, layout, layout$coord)
377383
}
378384
)
379385

tests/testthat/test-layer.r

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ test_that("if an aes is mapped to a function that returns NULL, it is removed",
6363
expect_identical(names(p[[1]]), c("x", "PANEL", "group"))
6464
})
6565

66+
test_that("layers are stateless except for the computed params", {
67+
df <- data.frame(x = 1:10, y = 1:10)
68+
p <- ggplot(df) +
69+
geom_col(aes(x = x, y = y), width = 0.8, fill = "red")
70+
col_layer <- as.list(p$layers[[1]])
71+
stateless_names <- setdiff(names(col_layer), c("computed_geom_params", "computed_stat_params"))
72+
invisible(ggplotGrob(p))
73+
expect_identical(as.list(p$layers[[1]])[stateless_names], col_layer[stateless_names])
74+
})
75+
6676
# Data extraction ---------------------------------------------------------
6777

6878
test_that("layer_data returns a data.frame", {

0 commit comments

Comments
 (0)