Suppose that a R package defines S3 classes representing data for
scatter points and lines for fits. It would be sensible to write the
autoplot
and autolayer
methods for both points and lines. Then we
could build a plot with autoplot
and add stuff with a sequence of
calls to autolayer
, possibly specifying new colour, fill, linetype
at each call.
library(ggplot2)
autolayer.myLines <- function(object, ...) {
geom_line(data = object,
mapping = aes(x = x, y = y, colour = .group, linetype = .group))
}
autoplot.myLines <- function(object, ...) {
ggplot() + autolayer(object, ...)
}
autolayer.myPoints <- function(object, ...) {
geom_point(data = object,
mapping = aes(x = x, y = y, colour = .group, shape = .group))
}
autoplot.myPoints <- function(object, ...) {
ggplot() + autolayer(object, ...)
}
set.seed(123)
xP <- runif(10)
## objects with class "myPoints"
myP1 <- data.frame(x = xP, y = xP + rnorm(10, sd = 0.1), .group = "points 1")
myP2 <- data.frame(x = xP, y = xP * xP + rnorm(10, sd = 0.1), .group = "points 2")
class(myP1) <- class(myP2) <- c("myPoints", "data.frame")
## objects with class "myLines"
xL <- seq(from = 0, to = 1, length.out = 80)
myL1 <- data.frame(x = xL, y = xL, .group = "line 1")
myL2 <- data.frame(x = xL, y = xL * xL, .group = "line 2")
class(myL1) <- class(myL2) <- c("myLines", "data.frame")
autoplot(myP1) + autolayer(myL1) + autolayer(myP2) + autolayer(myL2) +
scale_colour_manual(values = c("orangered", "green", "magenta", "SteelBlue"))
The nice point is that legends are updated when some new material is
added. However the legend created by the common colour
keyword is
quite confusing. It would make sense to have only two legends, one
for the points and one for the lines each with the elements of the
aesthetics in geom_point
and geom_line
. So shapes would be shown
for the "points" legend, but not for the "lines" one, as if the
legends arose from two ggplots using two data frames: one for the
points and one for the lines (see image below). So the question is: what is the best way
to get the two legends, making sure they are updated when more
autolayer
calls are added?
More generally some keywords entering in the definition of aesthetics
via aes
such as fill
have a quite different meaning across
geometries and it seems strange to gather these in a common legend as
is the case e.g. if geom_ribbon
and geom_point
are used in the
same plot both with aesthetics including fill
. Is there a simple
solution to avoid this default behaviour and generate legends from
aesthetics within geoms?