从ggplot2图表中删除图层

时间:2012-11-15 22:18:30

标签: 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))

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


编辑:接受@ mnel的答案,因为它有效。现在,我需要确定如何动态访问geom_ribbon图层,该图层在SO问题here中捕获。


编辑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
}

编辑3:请参阅下面接受的答案,了解最新版本的ggplot(&gt; = 2.x.y)

5 个答案:

答案 0 :(得分: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)

您将看到要删除第一层

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

p$layer <- p$layer[2]

现在构建并绘制p

p

请注意p$layer[[1]] <- NULL也可以。我同意@Andrie和@Joran关于在这些案例中的评论,这可能是有用的,并且不会期望这必然是可靠的。 enter image description here

答案 1 :(得分: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
}

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

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

让我们展示原始情节:

p

plot with text labels

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

p <- remove_geom(p, "GeomText")
p

plot without text labels

答案 2 :(得分:5)

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

library(gginnards)
p1 <- delete_layers(p, match_type = "GeomText")

有关其他示例的信息包的文档,以及有关修改图层顺序以及在任意位置插入新图层的配套函数的信息。

答案 3 :(得分:3)

@Kamil Slowikowski谢谢!很有用。但是我无法阻止自己在同一个主题上创建一个新的变体...希望比原始帖子或Kamil的更新版本更容易理解,也避免了一些任务。

__hash__

此版本在功能上与Kamil的功能完全相同,因此上面的用法示例不需要在此重复。

顺便说一句,这个函数可以很容易地根据stat的类而不是geom的类来选择图层。

#class Foo(object) Works since __hash__ is available in the base class 
class Foo:  #Why does this work? 
    def __init__(self):
        self.x = None
a = Foo()
print dir(a) # No __hash__ magic method
print hash(a) 
# Expecting an error like non-hashable or __hash__ not implemented 
# or something similar

答案 4 :(得分:1)

@Kamil和@Pedro非常感谢!对于感兴趣的人,还可以扩展Pedro的功能以仅选择特定的图层,如此处显示的last_only参数:

remove_geoms <- function(x, geom_type, last_only = T) {
  # Find layers that match the requested type.
  selector <- sapply(x$layers,
                     function(y) {
                       class(y$geom)[1] == geom_type
                     })
  if(last_only) 
    selector <- max(which(selector))
  # Delete the layers.
  x$layers[selector] <- NULL
  x
}

回到@Kamil的示例情节:

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_point(color = "green") + geom_point(size = 5, color = "red")

p

enter image description here

p %>% remove_geoms("GeomPoint")

enter image description here

p %>% remove_geoms("GeomPoint")  %>% remove_geoms("GeomPoint")

enter image description here