When I add a manual scale like in the example below. I get the following error message:
"Warning message: In if (self$guide == "none") return() : the condition has length > 1 and only the first element will be used"
What is causing this error message and how do I solve it?
Your help is much appreciated!
d <- data.frame(week = seq(1, 52, 1),
revenue = round(runif(52, 0, 100)), 0)
p <- ggplot(data = d, aes(x = week, y = revenue, fill = 'lightskyblue')) +
geom_bar(stat = 'identity', colour = 'black')
p <- p + scale_fill_identity(name = NULL,
guide = guide_legend(label.position = 'top'),
labels = c('2019'))
p
Upvoted for a self-contained MCVE, though I'd like to emphasize that you got a warning message, not an error. In this particular case, you don't need to fix anything. You can ignore the message, as the code works perfectly fine as intended.
As @r2evans noted, this is due to the scale_*_identity
code [found here]. As described in ?scale_fill_identity
, these scales do not produce a legend by default, though you can override that by substituting the guide = "none"
argument with other types of guides.
How it's supposed to work:
This legend-creation behaviour is coded in the train
function for ScaleDiscreteIdentity
/ ScaleContinuousIdentity
, which checks to see whether the guide parameter's value is "none". If so, create no legend. Otherwise, use the train
function from ScaleDiscrete
/ ScaleContinuous
to create the appropriate legend:
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)
}
)
The examples in ?scale_fill_identity
indicate that guide = "legend"
can be used instead of guide = "none"
. In practice, guide = guide_legend(...)
can also be used. In fact, ?guides
states:
guide = "legend"
inscale_*
is syntactic sugar forguide = guide_legend()
How it actually works (at least based on my current version 3.1.0):
For scale_*_identity
, there is a subtle difference between guide = "legend"
and guide = guide_legend(...)
. I've trimmed down the MCVE to illustrate the point:
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")
Both p1 and p2 results in the same legend, yet p1 triggers the warning, while p2 does not. (p3, of course, uses the default option and triggers no warning.) The reason for this difference lies in their fill scales, which can be found at 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
has 21 items, while p2$scales$scales[[1]]$guide
and p3$scales$scales[[1]]$guide
each comprises of a single character string. As such, when the train
function checks for self$guide == "none"
, p1 returns a list of TRUE / FALSE values, one for each item, while p2 and p3 returns a single 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
Since the train
function only expects a single value to be returned from its self$guide == "none"
check, p1 triggers the warning message for condition length > 1.
Does it matter:
Not really. When faced with a list of 21 TRUE / FALSE values from p1, the train
function only looks at the first one---which is FALSE because p1$scales$scales[[1]]$guide$title
's default value is waiver()
. So p1's guide = guide_legend()
checks out the same way as p2's guide = "legend"
. You can ignore the warning and carry on.
... Just don't name your legend title "none" within guide_legend
:
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
Should it be addressed anyway:
Yes, though I'd say it's not a critical bug, as the code generally behaves as intended (p4 above is a fringe case).
I imagine the fix should be pretty simple anyway, e.g.:
# this
if (all(self$guide == "none")) return()
# instead of this
if (self$guide == "none") return()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With