As part of an effort to remove a specific geom from a plot I've already created (SO link here), I'd like to dynamically determine the geom type of each layer of a ggplot2 object.
Assuming I don't know the order in which I added layers, is there a way to dynamically find layers with a specific geom? If I print out the layers like I do below I can see that the layers are stored in a list, but I can't seem to access the geom type.
library(ggplot2)
dat <- data.frame(x=1:3, y=1:3, ymin=0:2, ymax=2:4)
p <- ggplot(dat, aes(x=x, y=y)) + geom_ribbon(aes(ymin=ymin, ymax=ymax), alpha=0.3) + geom_line()
p$layers
[[1]]
mapping: ymin = ymin, ymax = ymax
geom_ribbon: na.rm = FALSE, alpha = 0.3
stat_identity:
position_identity: (width = NULL, height = NULL)
[[2]]
geom_line:
stat_identity:
position_identity: (width = NULL, height = NULL)
I'm not familiar with proto objects and things I've tried from the proto documentation don't seem to work (e.g. p$layers[[1]]$str()
).
Thanks to the answers below I was able to come up with a function that removes a layer dynamically:
remove_geom <- function(ggplot2_object, geom_type) {
layers <- lapply(ggplot2_object$layers, function(x) if(x$geom$objname == geom_type) NULL else x)
layers <- layers[!sapply(layers, is.null)]
ggplot2_object$layers <- layers
ggplot2_object
}
ggplot 2.2 update: If what you want is a character string naming the geom type, you can use:
sapply(p$layers, function(x) class(x$geom)[1])
which yields the first class name for the geom object of each layer. In the OP's example:
[1] "GeomRibbon" "GeomLine"
The code in the answers above no longer give the results shown for version 2.2 The accepted answer yields two NULL values, and the other answer yields full ggproto
objects.
Edit: This answer is no longer current. It worked when the question was asked and presumably for quite some time after but for an answer that works with ggplot2 >= 2.2.0 see https://stackoverflow.com/a/43982598/1003565
If we're just looking to get the geom name for each item this appears to be in the $geom$objname part of each layer.
p$layers[[1]]$geom$objname
#[1] "ribbon"
lapply(p$layers, function(x){x$geom$objname})
#[[1]]
#[1] "ribbon"
#
#[[2]]
#[1] "line"
As an added note - the reason you couldn't use the p$layers[[1]]$str()
syntax is (probably) because you didn't explicitly load the proto package. ggplot2 uses it internally but it imports it instead of using Depends. Notice the difference:
> library(ggplot2)
> dat <- data.frame(x=1:3, y=1:3, ymin=0:2, ymax=2:4)
> p <- ggplot(dat, aes(x=x, y=y)) + geom_ribbon(aes(ymin=ymin, ymax=ymax), alpha=0.3) + geom_line()
> p$layers
[[1]]
mapping: ymin = ymin, ymax = ymax
geom_ribbon: na.rm = FALSE, alpha = 0.3
stat_identity:
position_identity: (width = NULL, height = NULL)
[[2]]
geom_line:
stat_identity:
position_identity: (width = NULL, height = NULL)
> p$layers[[1]]$str()
Error: attempt to apply non-function
> library(proto)
> p$layers[[1]]$str()
proto object
$ geom_params:List of 2
$ mapping :List of 2
$ stat_params: Named list()
$ stat :proto object
..parent: proto object
.. .. parent: proto object
$ inherit.aes: logi TRUE
$ geom :proto object
..parent: proto object
.. .. parent: proto object
$ position :proto object
..parent: proto object
.. .. parent: proto object
.. .. .. parent: proto object
$ subset : NULL
$ data : list()
..- attr(*, "class")= chr "waiver"
$ show_guide : logi NA
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With