简答
支持独立的 MCVE,但我想强调的是,您收到了 警告 消息,而不是错误。在这种特殊情况下,您无需修复任何内容。您可以忽略该消息,因为代码可以正常工作。
更长的解释
正如@r2evans 所说,这是由于scale_*_identity 代码[found here]。如?scale_fill_identity 中所述,默认情况下这些比例不会生成图例,但您可以通过将guide = "none" 参数替换为其他类型的指南来覆盖它。
它应该如何工作:
此图例创建行为在train 函数中为ScaleDiscreteIdentity / ScaleContinuousIdentity 编码,该函数检查引导参数的值是否为“none”。如果是这样,请不要创建图例。否则,使用ScaleDiscrete / ScaleContinuous 中的train 函数来创建适当的图例:
ScaleDiscreteIdentity <- ggproto("ScaleDiscreteIdentity", ScaleDiscrete,
...,
train = function(self, x) {
# do nothing if no guide, otherwise train so we know what breaks to use
if (self$guide == "none") return()
ggproto_parent(ScaleDiscrete, self)$train(x)
}
)
ScaleContinuousIdentity <- ggproto("ScaleContinuousIdentity", ScaleContinuous,
...,
train = function(self, x) {
# do nothing if no guide, otherwise train so we know what breaks to use
if (self$guide == "none") return()
ggproto_parent(ScaleContinuous, self)$train(x)
}
)
?scale_fill_identity 中的示例表明可以使用guide = "legend" 代替guide = "none"。在实践中,guide = guide_legend(...) 也可以使用。事实上,?guides 表示:
scale_* 中的guide = "legend" 是guide = guide_legend() 的语法糖
实际工作原理(至少基于我当前的 3.1.0 版本):
对于scale_*_identity,guide = "legend" 和guide = guide_legend(...) 之间存在细微差别。我已经削减了 MCVE 来说明这一点:
p <- ggplot(data = d,
aes(x = week, y = revenue, fill = 'lightskyblue')) +
geom_col()
p1 <- p + scale_fill_identity(guide = guide_legend())
p2 <- p + scale_fill_identity(guide = "legend")
p3 <- p + scale_fill_identity(guide = "none")
p1 和 p2 产生相同的图例,但 p1 触发警告,而 p2 不会。 (当然p3使用默认选项,不会触发警告。)造成这种差异的原因在于它们的填充比例,可以在p<1/2/3>$scales$scales[[1]]找到:
> p1$scales$scales[[1]]$guide
$`title`
list()
attr(,"class")
[1] "waiver"
$title.position
NULL
$title.theme
NULL
... #omitted for space. it goes on for a while
> p2$scales$scales[[1]]$guide
[1] "legend"
> p3$scales$scales[[1]]$guide
[1] "none"
p1$scales$scales[[1]]$guide 有 21 项,而 p2$scales$scales[[1]]$guide 和 p3$scales$scales[[1]]$guide 各包含一个字符串。因此,当train 函数检查self$guide == "none" 时,p1 返回一个 TRUE / FALSE 值列表,每个项目一个,而 p2 和 p3 返回一个 TRUE / FALSE。
> p1$scales$scales[[1]]$guide == "none"
title title.position title.theme title.hjust title.vjust label
FALSE FALSE FALSE FALSE FALSE FALSE
label.position label.theme label.hjust label.vjust keywidth keyheight
FALSE FALSE FALSE FALSE FALSE FALSE
direction override.aes nrow ncol byrow reverse
FALSE FALSE FALSE FALSE FALSE FALSE
order available_aes name
FALSE FALSE FALSE
> p2$scales$scales[[1]]$guide == "none"
[1] FALSE
> p3$scales$scales[[1]]$guide == "none"
[1] TRUE
由于train 函数只期望从其self$guide == "none" 检查返回单个值,因此p1 会触发条件长度> 1 的警告消息。
有没有关系:
不是真的。当面对来自 p1 的 21 个 TRUE / FALSE 值列表时,train 函数只查看第一个 --- 这是 FALSE,因为 p1$scales$scales[[1]]$guide$title 的默认值是 waiver()。所以 p1 的 guide = guide_legend() 与 p2 的 guide = "legend" 的签出方式相同。您可以忽略警告并继续。
...只是不要在guide_legend 中将您的图例标题命名为“none”:
p4 <- p + scale_fill_identity(guide = guide_legend(title = "none"))
# this will cause the legend to disappear, because the first value in
# p4$scales$scales[[1]]$guide == "none" will actually be TRUE
还是应该解决这个问题:
是的,虽然我想说这不是一个严重的错误,因为代码通常按预期运行(上面的 p4 是一个边缘案例)。
我想修复应该很简单,例如:
# this
if (all(self$guide == "none")) return()
# instead of this
if (self$guide == "none") return()