我试图用一个新的类来扩展ggplot2
,在这个例子中我们将称之为foo
。目标是编写一个+.foo
方法,用于代替+.gg
。然而,我遇到了一个“不兼容方法”的问题
设置
目前我可以写ggplot_add.foo_layer
,这将使plot
到我的foo
类,然后添加相应的层正常。
其思想是,一旦打印对象继承了foo
,它将在添加下一个图层时分派到+.foo
。
我想这样做的原因是因为我想检查foo
对象的结构是否仍然有效/与传入层兼容。这将防止我不得不为ggplot_build
编写方法。
代码定义
library(ggplot2)
`+.foo` <- function(e1, e2){
cat("Using foo ggplot +") # for Debugging
NextMethod() #ideally just dispatches to `+.gg`
}
ggplot_add.foo_layer <- function(object, plot, object_name) {
plot <- as_foo(plot)
ggplot2:::add_ggplot(plot, object$layer, object_name)
}
as_foo <- function(x){
if(!is_foo(x)){
class(x) <- c("foo", class(x))
}
x
}
is_foo <- function(x) inherits(x, "foo")
foo_layer <- function(x) structure(list(layer = x), class = "foo_layer")
错误
p1 <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
geom_point()
class(p1)
#[1] "gg" "ggplot"
p1 + geom_density(aes(y = after_stat(density)))
p2 <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
foo_layer(geom_point())
class(p2)
#[1] "foo" "gg" "ggplot"
p2 + geom_density(aes(y = after_stat(density)))
#Error in p2 + geom_density(aes(y = after_stat(density))) :
# non-numeric argument to binary operator
#In addition: Warning message:
#Incompatible methods ("+.foo", "+.gg") for "+"
从上面的代码中,p1 + geom_*
执行得很好。但是,由于上面关于不兼容方法的错误,p2 + geom_*
无法执行。从我对S3方法调度的了解来看,我不明白为什么这不起作用。有人能解释一下为什么会这样吗?或者我如何补救?
理想情况下,我不需要写一个方法ggplot_build.foo
,因为我希望其他包的ggplot_build
可以被使用,如果它们存在的话(例如gganimate
)。
2条答案
按热度按时间enxuqcxy1#
你可以做的一件事是覆盖ggplot 2:+gg方法来支持S3中的双重分派。如果你正在编写一个包,这不是一个很好的行为,但它完成了任务。注意,这种顽皮的行为并没有阻止其他包覆盖ggplot的函数(看看你,ggtern)。
创建于2021-01-20由reprex package(v0.3.0)
ddhy6vgd2#
感谢resource provided by @teunbrand,我们可以使用S4安全地使用
+
进行调度编辑----
看起来在会话之间,这段代码实际上并没有在我定义的S4方法
+
上调度。由于某种原因,它仍然在调度到+.gg
。我会做一些关于调度的研究,但目前,下面的代码不起作用。S4类定义
对于所有意图和目的,新的
foo
对象的“行为”与标准的ggplot
对象类似。此外,其他包(如
gganimate
)仍将返回Foo
对象,但会调用自己的ggplot_build
S3方法。