ggplot2 0.9.3中美学继承和annotation_custom的行为

6

针对我最近的一个问题这个问题有点不同,使用更简单的例子更完整地解释了问题。以下是两组数据和三个函数。第一个函数绘制了一些点和一个预期的圆:

library("ggplot2")
library("grid")

td1 <- data.frame(x = rnorm(10), y = rnorm(10))

tf1 <- function(df) { # works as expected
    p <- ggplot(aes(x = x, y = y), data = df)
    p <- p + geom_point(color = "red")
    p <- p + annotation_custom(circleGrob())
    print(p)
}

tf1(td1)

下一个示例似乎要求精确的样本图,但代码略有不同。它不会报错,但不会绘制圆形:

tf2 <- function(df) { # circle isn't draw, but no error either
    p <- ggplot()
    p <- p + geom_point(data = df, aes(x = x, y = y), color = "red")        
    p <- p + annotation_custom(circleGrob())
    print(p)
    }

tf2(td1)

最后一个涉及到更复杂的审美,当你尝试创建圆形时会得到一个空的层。
td3 <- data.frame(r = c(rnorm(5, 5, 1.5), rnorm(5, 8, 2)),
    f1 = c(rep("L", 5), rep("H", 5)), f2 = rep(c("A", "B"), 5))

tf3 <- function(df) {
    p <- ggplot()
    p <- p + geom_point(data = df, 
        aes(x = f1, y = r, color = f2, group = f2))     
#   p <- p + annotation_custom(circleGrob()) # comment out and it works
    print(p)
    }

tf3(td3)

现在,我怀疑这里的问题不是代码,而是我没有理解ggplot2的内部工作原理。 我确实需要一个解释,为什么在第二种情况下圆圈没有被绘制,以及为什么在第三种情况下层是空的。 我查看了annotation_custom的代码,它有一个硬编码的inherit.aes = TRUE,我认为这就是问题所在。我不明白为什么这个函数需要任何美学元素(请参见其文档)。我尝试了几种方法来覆盖它并设置inherit.aes = FALSE,但我无法完全进入命名空间并使其生效。我试图检查ggplot2创建的对象,但这些proto对象嵌套得非常深,很难解读。


问题所在是美学继承和annotation_custom - Faheem Mitha
@FaheemMitha 可能是这样,但我并没有真正深入研究过图例。我看到你一直在努力挖掘,试图找出答案。我在新版本(0.9.3)中编写ggplot2函数时遇到了很大的麻烦,以至于我放弃了它,并在lattice中重新编写了函数(发抖)。但至少在lattice中,事情就是它们所呈现的那样。我在ggplot2 0.9.3中一直在追逐自己的尾巴,因为事情并不像它们表面上看起来那样。我观察到的其中一个重大变化是stat_summary,他们进行了更改,然后由于问题而进行了更改;我需要它更加稳定!祝好运! - Bryan Hanson
你找到解决方案了吗?我有一个非常复杂的ggplot,并想给它一个非常简单的annotation_custom - stevec
1
@stevec 多年未碰,抱歉。请确保您使用的是最新的 ggplot2 版本。 - Bryan Hanson
@stevec 在这里有广泛的讨论(https://github.com/tidyverse/ggplot2/issues/756),但按照ggplot2的标准,这已经是古老的了。我建议您制作一个MWE并在此处提出新问题。 - Bryan Hanson
显示剩余6条评论
1个回答

2
回答这个问题:
“我不明白为什么这个函数需要任何美学。”
实际上,annotation_custom 需要x和y aes来缩放它的grob,并在使用native单位之后使用。基本上它是这样做的:
  x_rng <- range(df$x, na.rm = TRUE)                            ## ranges of x :aes x
  y_rng <- range(df$y, na.rm = TRUE)                            ## ranges of y :aes y
  vp <- viewport(x = mean(x_rng), y = mean(y_rng),              ##  create a viewport
                 width = diff(x_rng), height = diff(y_rng),
                 just = c("center","center"))
  dd <- editGrob(grod =circleGrob(), vp = vp)                  ##plot the grob in this vp 

为了说明这一点,我将一个grob添加到一个用作比例的虚拟图中。第一个是大比例尺,第二个是小比例尺。
base.big   <- ggplot(aes(x = x1, y = y1), data = data.frame(x1=1:100,y1=1:100))
base.small <- ggplot(aes(x = x1, y = y1), data = data.frame(x1=1:20,y1=1:1))

我定义了我的图形对象,使用原生的xmin、xmax、ymin、ymax比例尺。

annot <- annotation_custom(grob = circleGrob(),  xmin = 0, 
                                                 xmax = 20, 
                                                 ymin = 0, 
                                                 ymax = 1)

现在看一下 (base.big +annot) 和 (base.small + annot) 之间的比例差异(小点 / 大圆圈)。请注意,保留了 HTML 标签。
library(gridExtra)
grid.arrange(base.big+annot,
             base.small+annot)

enter image description here


感谢您的回答。我理解了您编写的代码以及为什么它有效,但我不确定它与我的问题有何关系。我评论不需要美学的原因是该函数不使用美学(从文档和代码中清楚地表明)。当然,它必须按比例缩放到vp大小,但这不是一个美学问题(问题可能是我没有正确使用这些术语)。annotation_custom确实使用inherit.aes(内部使用,而不是参数),但我不清楚它继承自哪里。 - Bryan Hanson
xy有默认值,因此您不必传递它们。 - baptiste
你写道:“现在看一下(base.big + annot)和(base.big + annot)之间的刻度差异(小点/大圆)。我猜你的意思是(base.small + annot)。” 此外,“Bascially” 拼错了(第三行)。 - Faheem Mitha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接