skan
skan

Reputation: 7720

Force ggplot2 to use the same labels and colors on the legends for two plots

I'm trying to create several plots with ggplot2, and I'd like it to assign always the same color to the each factor type.

Here you have a toy example.

mydata <- data.frame(from=rep(c("b","c"), each=15),
    to=rep(c("a","b","c"), each=10), 
    value=c(rep(1:5,5:1),rep(1:5,1:5)) )

I first convert the categories to factors in order to assign always the same value and because it worked on other plots I did.

I want to create two density plots (or similar) from the value grouped by categories in two ways, one using the categories of the "from" column, another one with the categories of the "to" column, using the same legend.

niv <- c("a", "b", "c")
colo <- c("black", "red", "blue")

mydata$from <- factor(mydata$from, levels=niv)
mydata$to <- factor(mydata$to, levels=niv)

And now I generate the plots. First with grouping by the "from" column.

ggplot(mydata) +  stat_density(geom="line",size=0.8,
 position = "identity", aes(x=value, color=from)) +
  scale_colour_manual(name="Type",labels = niv, 
  values=colo)  +  theme_bw()

enter image description here

As you can see it doesn't produce the desired plot because it shows an "a" factor but it doesn't exist on the "from" column.

And now grouping by the "to" column.

ggplot(mydata) +  stat_density(geom="line",size=0.8,
  position = "identity", aes(x=value, color=to)) +
  scale_colour_manual(name="Type",labels = niv, 
  values=colo)  +  theme_bw()

enter image description here

It works as expected.

Now I try to produce again the first plot without the labels parameter.

ggplot(mydata) +  stat_density(geom="line",size=0.8,
  position = "identity", aes(x=value, color=from)) +
  scale_colour_manual(name="Type", values=colo)  +  
  theme_bw()

enter image description here

Now it labels properly the categories but the color don't match with the second plot.

How can I do it?

The real problem has more categories and many values.

Upvotes: 1

Views: 1988

Answers (1)

Clemens Hug
Clemens Hug

Reputation: 497

You could use a named vector in scale_color_manual to map Type explicitly to colors:

color_map <- c("a" = "black", "b" = "red", "c" = "blue")
scale_colour_manual(values=color_map)

From the help(scale_color_manual):

values

a set of aesthetic values to map data values to. If this is a named vector, then the values will be matched based on the names. If unnamed, values will be matched in order (usually alphabetical) with the limits of the scale. Any data values that don't match will be given na.value.

Here is the full code that, I believe, produces the output that you want:

library(tidyverse)

mydata <- data.frame(
  from = rep(c("b", "c"), each = 15),
  to = rep(c("a", "b", "c"), each = 10),
  value = c(rep(1:5, 5:1), rep(1:5, 1:5))
)

niv <- c("a", "b", "c")
colo <- c("black", "red", "blue")

color_map <- set_names(colo, niv)

mydata$from <- factor(mydata$from, levels = niv)
mydata$to <- factor(mydata$to, levels = niv)

ggplot(mydata) + stat_density(
  geom = "line", size = 0.8,
  position = "identity", aes(x = value, color = from)
) +
  scale_colour_manual(name = "Type", values = color_map) + theme_bw()

ggplot(mydata) + stat_density(
  geom = "line", size = 0.8,
  position = "identity", aes(x = value, color = to)
) +
  scale_colour_manual(
    name = "Type",
    values = color_map
  ) + theme_bw()

Upvotes: 2

Related Questions