跟进最近的mine问题,这个问题有点不同,并使用更简单的示例更充分地说明问题。以下是两个数据集和三个函数。第一个按预期绘制了一些点和一个圆圈:
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
对象嵌套得非常深,难以破译。
答案 0 :(得分:2)
回答这个问题:
“我不明白为什么这个功能需要任何美学”。
实际上annotation_custom
需要x和y来缩放其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添加到一个虚拟图中,用作我的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))
我定义了我的grob,看我使用xmin,xmax,ymin,ymax的原生比例
annot <- annotation_custom(grob = circleGrob(), xmin = 0,
xmax = 20,
ymin = 0,
ymax = 1)
现在查看(base.big +annot
)和(base.small + annot
)之间的比例差异(小点 / 大圈)。
library(gridExtra)
grid.arrange(base.big+annot,
base.small+annot)