从ggplot2图表中删除图层

Eri*_*lts 29 r ggplot2

我想从ggplot2创建的网格对象中删除layer(在本例中为结果geom_ribbon).一旦它已经成为对象的一部分,有没有办法可以删除它?

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()

# This has the geom_ribbon
p

# This overlays another ribbon on top
p + geom_ribbon(aes(ymin=ymin, ymax=ymax, fill=NA))
Run Code Online (Sandbox Code Playgroud)

我希望这个功能允许我在不那么复杂的情节之上构建更复杂的图.我正在使用返回网格对象的函数,然后在完全组装后打印出最终的图.基础图有一条线,geom_ribbon周围有相应的误差条().较复杂的绘图将具有多条线,并且多个重叠geom_ribbon对象分散注意力.我想从多行的图中删除它们.此外,我将能够使用facet或其他ggplot2功能快速创建替代版本.


编辑:接受@ mnel的答案,因为它有效.现在我需要确定如何动态地访问geom_ribbon层,这是在SO问题捕获这里.


编辑2:为了完整性,这是我为解决这个问题而创建的函数:

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
}
Run Code Online (Sandbox Code Playgroud)

编辑3:请参阅下面接受的答案,了解最新版本的ggplot(> = 2.xy)

mne*_*nel 19

如果你看看

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)
Run Code Online (Sandbox Code Playgroud)

您将看到要删除第一个图层

您可以通过将图层重新定义为列表中的第二个组件来完成此操作.

p$layer <- p$layer[2]
Run Code Online (Sandbox Code Playgroud)

现在建立并策划 p

p
Run Code Online (Sandbox Code Playgroud)

Note that p$layer[[1]] <- NULL would work as well. I agree with @Andrie and @Joran's comments regarding in wehat cases this might be useful, and would not expect this to be necessarily reliable. 在此输入图像描述


Kam*_*ski 15

对于ggplot2版本2.2.1,我不得不修改建议的remove_geom函数,如下所示:

remove_geom <- function(ggplot2_object, geom_type) {
  # Delete layers that match the requested type.
  layers <- lapply(ggplot2_object$layers, function(x) {
    if (class(x$geom)[1] == geom_type) {
      NULL
    } else {
      x
    }
  })
  # Delete the unwanted layers.
  layers <- layers[!sapply(layers, is.null)]
  ggplot2_object$layers <- layers
  ggplot2_object
}
Run Code Online (Sandbox Code Playgroud)

以下是如何使用它的示例:

library(ggplot2)

set.seed(3000)
d <- data.frame(
  x = runif(10),
  y = runif(10),
  label = sprintf("label%s", 1:10)
)

p <- ggplot(d, aes(x, y, label = label)) + geom_point() + geom_text()
Run Code Online (Sandbox Code Playgroud)

让我们展示原始情节:

p
Run Code Online (Sandbox Code Playgroud)

情节与文本标签

现在让我们删除标签并再次显示情节:

p <- remove_geom(p, "GeomText")
p
Run Code Online (Sandbox Code Playgroud)

没有文字标签的情节


Ped*_*alo 7

@卡米尔·斯洛维科夫斯基 谢谢!很有用。然而,我无法阻止自己在同一主题上创建一个新的变体……希望比原来的帖子或卡米尔的更新版本更容易理解,同时也避免了一些作业。

remove_geoms <- function(x, geom_type) {
  # Find layers that match the requested type.
  selector <- sapply(x$layers,
                     function(y) {
                       class(y$geom)[1] == geom_type
                     })
  # Delete the layers.
  x$layers[selector] <- NULL
  x
}
Run Code Online (Sandbox Code Playgroud)

该版本在功能上与Kamil的功能相同,因此上面的使用示例此处无需重复。

顺便说一句,这个函数可以很容易地适应根据统计的类而不是几何的类来选择图层。

remove_stats <- function(x, stat_type) {
  # Find layers that match the requested type.
  selector <- sapply(x$layers,
                     function(y) {
                       class(y$stat)[1] == stat_type
                     })
  # Delete the layers.
  x$layers[selector] <- NULL
  x
}
Run Code Online (Sandbox Code Playgroud)


Ped*_*alo 5

由于这个问题看起来很有趣,我扩展了我的'ggpmisc'包,其中的函数用于操作ggplot对象中的层(目前在​​包'gginnards'中).在我之前对同一个问题的回答中,这些函数是更加精致的例子.但是,请注意,在大多数情况下,这不是最好的工作方式,因为它违反了图形语法.在大多数情况下,可以通过操作员以正常方式组装同一图形的不同变体+,可能将图层组"打包"到列表中以具有可以简化复杂图形的组装的组合构建块.在特殊情况下,我们可能希望通过更高级别的函数编辑现有的绘图或绘图输出,其定义我们无法修改.在这种情况下,这些层操作功能可能很有用.上面的例子变成了.

library(gginnards)
p1 <- delete_layers(p, match_type = "GeomText")
Run Code Online (Sandbox Code Playgroud)

有关其他示例的信息,请参阅软件包的文档,以及有关用于修改图层顺序以及在任意位置插入新图层的配套函数的信息.