-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
There are a number of issues that have been opened expressing surprise at the handling of Layers where aes()
does not refer to the data and the data is not specified.
library(ggplot2)
ggplot(data.frame(x = 1:5)) +
geom_text(aes(x = 1, y = 1, label = "annotation"))
This plot contains 5 copies of the "annotation" label, since the geom_text()
layer inherits the plot data, and the aesthetics are recycled to the length of the layer data (if they are length 1). This usually only noticed for partially transparent objects (#2829, #2529, #2790), but has also caused errors in geom_boxplot()
(#3316).
This is usually caused by slightly spurious ggplot2 usage by users who do not create and map a data frame but instead wire vectors directly into one or more layers directly by aes()
. The workarounds are:
- Actually create a data frame and map it. This is obviously preferred but can get verbose for something like
geom_boxplot()
withstat = "identity"
, where evenaes_all(c("ymin", "lower", "middle", "upper", "ymax"))
is pretty verbose. - Use
annotate()
, although this doesn't work with facets when there are non-position aesthetics with a length != 1 ( Annotation breaks with facets #3305 (comment) ), and doesn't always train the position scales properly for position aesthetics that are not (x|y), (x|y)min, or (x|y)max (Consolidate definition of position aesthetics #3342). - For the layer
data
, pass a non-null value for whichggplot2:::empty()
returnsTRUE
(e.g.,data = data.frame()
). This keeps the layer from inheriting the plot data, since there is noinherit.data
argument of a plot layer, although it doesn't really make sense.
I think there are some options to discourage this practice and/or make it less verbose to do the right thing.
- Add an
inherit.data
argument that can be set toFALSE
, such that one can safely and predictably pass vectors intoaes()
. - Make the
mapping
a function of the data and make a function that returns an automapped data frame. We already sort of do this forgeom_sf()
, where we automatically map thegeometry
column fordata
of classsf
. Then, one could do something likegeom_text(data = mapped_df(x = 1, y = 1, label = "annotation"))
, which would generate the appropriate mapping. - Fix
annotate()
so that it works with all position aesthetics and with facets. - Warn when users supply a mapping that does not refer to data (this was recently vetoed, see Warn about discouraged aes() usage during plot build #3346)