A partial solution to my problem is found here. I will show how that solution works and what features are still lacking to meet my needs. For consistency, I use a sample data set that is similar to the one from the other thread:
library(ggplot2)
library(reshape2)
library(tidyverse)
df <- data.frame(x = c(1:5), a = c(1,2,3,3,3), b = c(1,1.1,1.3,1.5,1.5))
df <- mutate(df, log2 = log2(x))
df <- df <- melt(df, c("x", "log2"))
An initial plot of the data (created by the following code) has the shape
and color
aesthetics in separate legends, which is undesirable:
ggplot(df) +
geom_point(aes(x, value, colour = variable, shape = variable), size = 3) +
geom_line(aes(x, log2, color = "log2(x)"), size = 1.5)
The solution proposes using guides()
and override.aes
to combine these into a single legend, which is certainly an improvement over the original plot:
ggplot(df) +
geom_point(aes(x, value, colour = variable, shape = variable), size = 3) +
geom_line(aes(x, log2, color = "log2(x)"), size = 1.5) +
guides(shape = FALSE,
colour = guide_legend(override.aes = list(shape = c(16, 17, NA),
linetype = c("blank", "blank", "solid"))))
My issue is that I would like manual control of the color
aesthetic in both geom_point
and geom_line
. For example, I want to make the triangles light grey, the circles dark grey, and the log2(x)
line light blue. My understanding of how guides()
works is very limited, so the best I have been able to do is the following:
ggplot(df) +
geom_point(aes(x, value, shape = variable), color = "gray40", size = 3, data = filter(df, variable == "a")) +
geom_point(aes(x, value, shape = variable), color = "gray70", size = 3, data = filter(df, variable == "b")) +
geom_line(aes(x, log2, shape = "log2(x)"), color = "cadetblue2", size = 1.5) +
guides(shape = guide_legend(override.aes = list(color = c("gray40", "gray70", "cadetblue2"),
shape = c(16, 17, NA),
linetype = c("blank", "blank", "solid"))))
This seems like an improper use of the shape
aesthetic in geom_line
(given the warning generated), however it is almost the result I want. The problem now is that the legend icon for log2(x)
is missing. Ideally it should show a horizontal light blue line that matches the plot. Does anyone know how to achieve this and/or could better explain how the guides()
function is intended to be used?
I have also tried solutions using a combination of scale_color_manual()
, scale_linetype_manual()
, and scale_shape_manual()
(all with the same name
argument that way they should end up in a single legend). The issue with this approach has been that all 3 geom layers have a color
aesthetic, but only the first two have a shape
aesthetic and only the last one has a linetype
aesthetic. So even if all of the scale_xx_manual()
additions to ggplot
are set up correctly, the legends are not combined into a single one.
I have been stuck on this for a long time, so any help would be greatly appreciated. Thank you
Just create a manual color scale and that will change the colors in both the plot and the guide. In general, you always want to favor using a scale over overriding guide values because it removes the risk of making mistakes in the guide which could cause your visualization to lie.
ggplot(df) +
geom_point(aes(x, value, colour = variable, shape = variable), size = 3) +
geom_line(aes(x, log2, color = "log2(x)"), size = 1.5) +
scale_color_manual(values = c("a" = "gray40", "b" = "gray70", "log2(x)" = "cadetblue2")) +
guides(shape = FALSE,
colour = guide_legend(override.aes = list(shape = c(16, 17, NA),
linetype = c("blank", "blank", "solid"))))
Edit:
Here's a version that also avoids doing the guide override on shape:
ggplot(df) +
geom_point(aes(x, value, colour = variable, shape = variable, linetype = variable), size = 3) +
geom_line(aes(x, log2, color = "log2(x)", linetype = "log2(x)", shape = "log2(x)"), size = 1.5) +
scale_color_manual(values = c("a" = "gray40", "b" = "gray70", "log2(x)" = "cadetblue2")) +
scale_shape_manual(values = c("a" = 16, "b" = 17, "log2(x)" = NA)) +
scale_linetype_manual(values = c("a" = "blank", "b" = "blank", "log2(x)" = "solid"))
ggplot
will automatically combine legends when the name, labels, and direction are identical (1, 2), so you just have to make sure "a", "b", and "log2(x)" all have mappings to each aesthetic in the same order. In this case, we accomplish this by adding unnecessary mappings to the layers and ignoring the warnings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With