Short answer:
Just add a dummy geom_point
layer (transparent points) where shape
is mapped to the same level
as in geom_hline
.
geom_point(aes(shape = "int"), alpha = 0)
Longer answer:
Whenever possible, ggplot
merges / combines legends of different aes
thetics. For example, if colour
and shape
is mapped to the same variable, then the two legends are combined into one.
I illustrate this using simple data set with 'x', 'y' and a grouping variable 'grp' with two levels:
df <- data.frame(x = rep(1:2, 2), y = 1:4, grp = rep(c("a", "b"), each = 2))
First we map both color
and shape
to 'grp'
ggplot(data = df, aes(x = x, y = y, color = grp, shape = grp)) +
geom_line() +
geom_point(size = 4)

Fine, the legends for the aes
thetics, color
and shape
, are merged into one.
Then we add a geom_hline
. We want it to have a separate color from the geom_line
s and to appear in the legend. Thus, we map color
to a variable, i.e. put color
inside aes
of geom_hline
. In this case we do not map the color to a variable in the data set, but to a constant. We may give the constant a desired name, so we don't need to rename the legend entries afterwards.
ggplot(data = df, aes(x = x, y = y, color = grp, shape = grp)) +
geom_line() +
geom_point(size = 4) +
geom_hline(aes(yintercept = 2.5, color = "int"))

Now two legends appears, one for the color
aes
thetics of geom_line
and geom_hline
, and one for the shape
of the geom_point
s. The reason for this is that the "variable" which color
is mapped to now contains three levels: the two levels of 'grp' in the original data, plus the level 'int' which was introduced in the geom_hline
aes
. Thus, the levels in the color
scale differs from those in the shape
scale, and by default ggplot can't merge the two scales into one legend.
How to combine the two legends?
One possibility is to introduce the same, additional level for shape
as for color
by using a dummy geom_point
layer with transparent points (alpha
= 0) so that the two aes
thetics contains the same levels:
ggplot(data = df, aes(x = x, y = y, color = grp, shape = grp)) +
geom_line() +
geom_point(size = 4) +
geom_hline(aes(yintercept = 2.5, color = "int")) +
geom_point(aes(shape = "int"), alpha = 0) # <~~~~ a blank geom_point
Another possibility is to convert the original grouping variable to a factor
, and add the "geom_hline
level" to the original levels. Then use drop = FALSE
in scale_shape_discrete
to include "unused factor levels from the scale":
datadf$grp <- factor(df$grp, levels = c(unique(df$grp), "int"))
ggplot(data = df, aes(x = x, y = y, color = grp, shape = grp)) +
geom_line() +
geom_point(size = 4) +
geom_hline(aes(yintercept = 2.5, color = "int")) +
scale_shape_discrete(drop = FALSE)
Then, as you already know, you may use the guides
function to "override
" the shape
aes
thetics in the legend, and remove the shape from the geom_hline
entry by setting it to NA
:
guides(colour = guide_legend(override.aes = list(shape = c(16, 17, NA))))