The solution here lies in defining a new draw key. However, as Tjebo points out in the comments, it is difficult to customize the slopes this way because the data passed to the draw_key_*
functions does not contain all the aesthetic data - only that necessary to make the standard draw keys (linewidth, colour, fill, etc).
One way round this is to take advantage of the fact that ggplots are built using the ggproto
system, which itself is based on nested environments. A custom draw_key_*
function can be written that looks up the appropriate ancestor frame to find the whole aesthetic data set:
draw_key_custom <- function (data, params, size) {
colour <- data$colour
datalist <- get("data", parent.frame((10)))
i <- which(sapply(datalist, function(x) "slope" %in% names(x)))[1]
data <- datalist[[i]]
data <- data[data$colour == colour,]
slope <- data$slope
intercept <- (1 - slope)/2
y1 <- ifelse(abs(slope) > 1, (sign(slope) + 1)/2, intercept)
y2 <- ifelse(abs(slope) > 1, 1 - (sign(slope) + 1)/2, intercept + slope)
x1 <- ifelse(abs(slope) > 1, (y1 - intercept)/slope, 0)
x2 <- ifelse(abs(slope) > 1, (y2 - intercept)/slope, 1)
grid::segmentsGrob(x1, y1, x2, y2,
gp = grid::gpar(col = data$colour,
lwd = data$linewidth * 2))
}
This allows:
ggplot(df, mapping = aes(x = x, y = y)) +
geom_point() +
geom_abline(aes(slope = slope, intercept = 0, color = factor(group)),
key_glyph = draw_key_custom) +
coord_cartesian(xlim = c(0, 3), ylim = c(0, 3))

A couple of things I would point out are that:
- It is unusual and unnecessary to change slopes in a legend
- The resulting slopes will not necessarily match the slopes in the plot unless the aspect ratios of the legend keys fit the aspect ratio of the plotting panel. This ratio is not stable under plot resizing unless the aspect ratio is specified in
theme
- The above implementation is fragile to changes within
ggplot
, and may not work if multiple lines have the same colour.
Still, nice to know it can be done I suppose...