2
votes

I have some x and y data that I would like to compare on a ggplot2 scatter plot. I would like to add a unity line (y = x), twofold (y = 2x), half (y = x/2) and smoother lines to help making sense of the data but I cannot find how to add theses lines to the plot's legend. Any idea?

set.seed(123)
x <- runif(20, 1, 10)
y <- 0.8 * x + runif(20, -1, 1)
cat <- factor(c(rep("high", 10), rep("low", 10)))
d <- data.frame(x, y, cat)

ggplot(data=d) +
     geom_point(aes(x, y, colour=cat)) +
     geom_abline(aes(intercept=0, slope=1), col = "red") +
     geom_abline(aes(intercept=0, slope=0.5), col="blue", linetype="dotted") +
     geom_abline(aes(intercept=0, slope=2), col="blue", linetype="dashed")+
     geom_smooth(aes(x, y))

y vs x scatter plot in ggplot2

I would like the labels 'unity line', 'twofold', 'half', and 'smoother' to appear below the 'high' and 'low' labels in the legend.

Following User3640617's answer, I have tried the following code but the result is still not satisfying because the data points now have a linetype and a smoothing linetype linked to them in the legend.

ggplot(data=d) +
     geom_point(aes(x, y, colour=cat)) +
     geom_abline(aes(intercept=0, slope=1, colour="y = x")) +
     geom_abline(aes(intercept=0, slope=.5, colour="y = x/2")) +
     geom_abline(aes(intercept=0, slope=2, colour="y = 2x")) +
     geom_smooth(aes(x,y, colour="smooth")) +
     scale_color_manual(
        values=c("red", "darkgreen", "black", "blue", "red", "blue")) +
     scale_linetype_manual(
        values=c("blank", "blank", "solid", "dashed", "solid", "dotted")) +
     scale_shape_manual(values=c(1, 1, NA, NA, NA, NA))

Also, I do not seem to be able to manually change the tinetypes:

scatter plot with ablines and smoother

I know, I could simply choose other colors and there would be less confusion but it should be possible to have a legend with only points for points and lines for lines instead of having point and lines for both points and lines, or is it not?

ggplot2 seems to be bothered by the addition of color or linetype after the aes. The order of the categories seems to be changed when adding the lines to the legend.

3

3 Answers

7
votes

You can just map a character value to an unused aesthetic to trick ggplot into making a legend for you:

ggplot(data=d) +
  geom_point(aes(x, y, colour=cat)) +
  geom_abline(aes(intercept=0, slope=1, lty='unity line'), col = "red")

enter image description here

Use + scale_linetype(name = NULL) or labs(linetype = NULL) to remove the linetype legend title.

3
votes

I guess there is no way around having a second dataset containing your lines.

One way to get a second legend for the lines, is to map the lines by linetypes and hardcode the colors (followed by manually adjusting the colors in the legend).

This could be done like so:

library(ggplot2)

# 1 recreate the data
set.seed(123)
x <- runif(20, 1, 10)
y <- 0.8 * x + runif(20, -1, 1)
cat <- factor(c(rep("high", 10), rep("low", 10)))
d <- data.frame(x, y, cat)

# create the lines-data
d_lines <- data.frame(int = rep(0, 3),
                      sl = c(1, 0.5, 2),
                      col = c("red", "blue", "blue"),
                      lty = c("solid", "dotted", "dashed"))

# extract the linetypes from the data.frame (with names to map the values correclty)
ltys <- as.character(d_lines$lty)
names(ltys) <- as.character(d_lines$lty)
# extract the colors in the order that ggplot will put the names of the lines (dashed, dotted, solid)
cols <- as.character(d_lines$col)
cols <- cols[order(as.character(d_lines$lty))]

# plot the data
ggplot() +
  geom_point(data = d, aes(x, y, colour=cat)) +
  geom_smooth(data = d, aes(x, y)) +
  # add the two different line-colors
  geom_abline(data = d_lines[d_lines$col == "red", ], 
              aes(intercept = int, slope = sl, lty = lty), color = "red") +
  geom_abline(data = d_lines[d_lines$col == "blue", ], 
              aes(intercept = int, slope = sl, lty = lty), color = "blue") +
  # change the color of the legend
  scale_linetype_manual(name = "Linetype", values = ltys,
                        guide = guide_legend(override.aes = list(colour = cols)))
#> `geom_smooth()` using method = 'loess'

0
votes

Not a very neat solution perhaps, but you can create an additional data frame with the information for your unity line as follows:

dfabline <- data.frame(intercept=0, slope=1, group="unity line")

ggplot(data=d) +
  geom_point(aes(x, y, colour=cat)) +
  geom_abline(data=dfabline, aes(intercept=intercept, slope=slope,  colour=group))

You can specify the colour of the line and the points using scale_colour_manual.