Skip to content

Commit 9518944

Browse files
committed
allow creation of custom layers that have access to global plot data
1 parent 71cb174 commit 9518944

File tree

7 files changed

+62
-53
lines changed

7 files changed

+62
-53
lines changed

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ export(GeomText)
180180
export(GeomTile)
181181
export(GeomViolin)
182182
export(GeomVline)
183+
export(LayerSf)
183184
export(Layout)
184185
export(Position)
185186
export(PositionDodge)

R/layer.r

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
#' supplied parameters and aesthetics are understood by the `geom` or
4242
#' `stat`. Use `FALSE` to suppress the checks.
4343
#' @param params Additional parameters to the `geom` and `stat`.
44+
#' @param layer_class The type of layer object to be constructued. This allows
45+
#' the creation of custom layers. Can usually be left at its default.
4446
#' @keywords internal
4547
#' @examples
4648
#' # geom calls are just a short cut for layer
@@ -61,7 +63,7 @@ layer <- function(geom = NULL, stat = NULL,
6163
data = NULL, mapping = NULL,
6264
position = NULL, params = list(),
6365
inherit.aes = TRUE, check.aes = TRUE, check.param = TRUE,
64-
show.legend = NA) {
66+
show.legend = NA, layer_class = Layer) {
6567
if (is.null(geom))
6668
stop("Attempted to create layer with no geom.", call. = FALSE)
6769
if (is.null(stat))
@@ -130,7 +132,7 @@ layer <- function(geom = NULL, stat = NULL,
130132
)
131133
}
132134

133-
ggproto("LayerInstance", Layer,
135+
ggproto("LayerInstance", layer_class,
134136
geom = geom,
135137
geom_params = geom_params,
136138
stat = stat,
@@ -197,6 +199,11 @@ Layer <- ggproto("Layer", NULL,
197199
}
198200
},
199201

202+
# hook to allow a layer access to global plot data
203+
# as the plot is constructed.
204+
setup_layer = function(self, plot) {
205+
},
206+
200207
compute_aesthetics = function(self, data, plot) {
201208
# For annotation geoms, it is useful to be able to ignore the default aes
202209
if (self$inherit.aes) {

R/plot-construction.r

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ ggplot_add.list <- function(object, plot, object_name) {
153153
}
154154
#' @export
155155
ggplot_add.Layer <- function(object, plot, object_name) {
156+
# allow the layer to modify itself based on plot object
157+
# useful for layers that need to access the global data
158+
object$setup_layer(plot)
159+
156160
plot$layers <- append(plot$layers, object)
157161

158162
# Add any new labels

R/sf.R

Lines changed: 35 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,39 @@ stat_sf <- function(mapping = NULL, data = NULL, geom = "rect",
135135
na.rm = na.rm,
136136
legend = if (is.character(show.legend)) show.legend else "polygon",
137137
...
138-
)
138+
),
139+
layer_class = LayerSf
139140
)
140141
}
141142

142143

144+
# A special sf layer that auto-maps geometry data to the `geometry` aesthetic
145+
146+
#' @export
147+
#' @rdname ggsf
148+
#' @usage NULL
149+
#' @format NULL
150+
LayerSf <- ggproto("LayerSf", Layer,
151+
setup_layer = function(self, plot) {
152+
# Automatically determine the name of the geometry column
153+
# and add the mapping if it doesn't exist
154+
data <- self$layer_data(plot$data)
155+
156+
if (!is.null(data) && is_sf(data)) {
157+
geometry_col <- attr(data, "sf_column")
158+
} else {
159+
geometry_col <- "geometry"
160+
}
161+
162+
# isn't quite complete yet, should also check that the global mapping
163+
# doesn't contain a setting for geometry
164+
if (is.null(self$mapping$geometry)) {
165+
self$mapping$geometry <- as.name(geometry_col)
166+
}
167+
}
168+
)
169+
170+
143171
# geom --------------------------------------------------------------------
144172

145173
#' @export
@@ -234,17 +262,6 @@ sf_grob <- function(row, lineend, linejoin, linemitre) {
234262
geom_sf <- function(mapping = aes(), data = NULL, stat = "sf",
235263
position = "identity", na.rm = FALSE, show.legend = NA,
236264
inherit.aes = TRUE, ...) {
237-
238-
# Automatically determin name of geometry column
239-
if (!is.null(data) && is_sf(data)) {
240-
geometry_col <- attr(data, "sf_column")
241-
} else {
242-
geometry_col <- "geometry"
243-
}
244-
if (is.null(mapping$geometry)) {
245-
mapping$geometry <- as.name(geometry_col)
246-
}
247-
248265
c(
249266
layer(
250267
geom = GeomSf,
@@ -258,7 +275,8 @@ geom_sf <- function(mapping = aes(), data = NULL, stat = "sf",
258275
na.rm = na.rm,
259276
legend = if (is.character(show.legend)) show.legend else "polygon",
260277
...
261-
)
278+
),
279+
layer_class = LayerSf
262280
),
263281
coord_sf(default = TRUE)
264282
)
@@ -282,16 +300,6 @@ geom_sf_label <- function(mapping = aes(), data = NULL,
282300
inherit.aes = TRUE,
283301
fun.geometry = NULL) {
284302

285-
# Automatically determin name of geometry column
286-
if (!is.null(data) && is_sf(data)) {
287-
geometry_col <- attr(data, "sf_column")
288-
} else {
289-
geometry_col <- "geometry"
290-
}
291-
if (is.null(mapping$geometry)) {
292-
mapping$geometry <- as.name(geometry_col)
293-
}
294-
295303
if (!missing(nudge_x) || !missing(nudge_y)) {
296304
if (!missing(position)) {
297305
stop("Specify either `position` or `nudge_x`/`nudge_y`", call. = FALSE)
@@ -316,7 +324,8 @@ geom_sf_label <- function(mapping = aes(), data = NULL,
316324
na.rm = na.rm,
317325
fun.geometry = fun.geometry,
318326
...
319-
)
327+
),
328+
layer_class = LayerSf
320329
)
321330
}
322331

@@ -335,15 +344,6 @@ geom_sf_text <- function(mapping = aes(), data = NULL,
335344
show.legend = NA,
336345
inherit.aes = TRUE,
337346
fun.geometry = NULL) {
338-
# Automatically determin name of geometry column
339-
if (!is.null(data) && is_sf(data)) {
340-
geometry_col <- attr(data, "sf_column")
341-
} else {
342-
geometry_col <- "geometry"
343-
}
344-
if (is.null(mapping$geometry)) {
345-
mapping$geometry <- as.name(geometry_col)
346-
}
347347

348348
if (!missing(nudge_x) || !missing(nudge_y)) {
349349
if (!missing(position)) {
@@ -367,7 +367,8 @@ geom_sf_text <- function(mapping = aes(), data = NULL,
367367
na.rm = na.rm,
368368
fun.geometry = fun.geometry,
369369
...
370-
)
370+
),
371+
layer_class = LayerSf
371372
)
372373
}
373374

R/stat-sf-coordinates.R

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#' the line. `sf::st_zm()` is needed to drop Z and M dimension beforehand,
2424
#' otherwise `sf::st_point_on_surface()` may fail when the geometries have M
2525
#' dimension.
26-
#'
26+
#'
2727
#' @section Computed variables:
2828
#' \describe{
2929
#' \item{x}{X dimension of the simple feature}
@@ -33,10 +33,10 @@
3333
#' @examples
3434
#' if (requireNamespace("sf", quietly = TRUE)) {
3535
#' nc <- sf::st_read(system.file("shape/nc.shp", package="sf"))
36-
#'
36+
#'
3737
#' ggplot(nc) +
3838
#' stat_sf_coordinates()
39-
#'
39+
#'
4040
#' ggplot(nc) +
4141
#' geom_errorbarh(
4242
#' aes(geometry = geometry,
@@ -47,7 +47,7 @@
4747
#' stat = "sf_coordinates"
4848
#' )
4949
#' }
50-
#'
50+
#'
5151
#' @export
5252
#' @inheritParams stat_identity
5353
#' @inheritParams geom_point
@@ -62,16 +62,6 @@ stat_sf_coordinates <- function(mapping = aes(), data = NULL, geom = "point",
6262
show.legend = NA, inherit.aes = TRUE,
6363
fun.geometry = NULL,
6464
...) {
65-
# Automatically determin name of geometry column
66-
if (!is.null(data) && is_sf(data)) {
67-
geometry_col <- attr(data, "sf_column")
68-
} else {
69-
geometry_col <- "geometry"
70-
}
71-
if (is.null(mapping$geometry)) {
72-
mapping$geometry <- as.name(geometry_col)
73-
}
74-
7565
layer(
7666
stat = StatSfCoordinates,
7767
data = data,
@@ -84,7 +74,8 @@ stat_sf_coordinates <- function(mapping = aes(), data = NULL, geom = "point",
8474
na.rm = na.rm,
8575
fun.geometry = fun.geometry,
8676
...
87-
)
77+
),
78+
layer_class = LayerSf
8879
)
8980
}
9081

@@ -98,7 +89,7 @@ StatSfCoordinates <- ggproto(
9889
if (is.null(fun.geometry)) {
9990
fun.geometry <- function(x) sf::st_point_on_surface(sf::st_zm(x))
10091
}
101-
92+
10293
points_sfc <- fun.geometry(data$geometry)
10394
coordinates <- sf::st_coordinates(points_sfc)
10495
data$x <- coordinates[, "X"]

man/ggsf.Rd

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

man/layer.Rd

Lines changed: 5 additions & 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)