web-dev-qa-db-fra.com

Comment fusionner la couleur, le style de trait et la forme des légendes dans ggplot

Supposons que j'ai l'intrigue suivante dans ggplot:

ggplot graph

Il a été généré à l'aide du code ci-dessous:

x <- seq(0, 10, by = 0.2)
y1 <- sin(x)
y2 <- cos(x)
y3 <- cos(x + pi / 4)
y4 <- sin(x + pi / 4)
df1 <- data.frame(x, y = y1, Type = as.factor("sin"), Method = as.factor("method1"))
df2 <- data.frame(x, y = y2, Type = as.factor("cos"), Method = as.factor("method1"))
df3 <- data.frame(x, y = y3, Type = as.factor("cos"), Method = as.factor("method2"))
df4 <- data.frame(x, y = y4, Type = as.factor("sin"), Method = as.factor("method2"))

df.merged <- rbind(df1, df2, df3, df4)

ggplot(df.merged, aes(x, y, colour = interaction(Type, Method), linetype = Method, shape = Type)) + geom_line() + geom_point()

Je voudrais avoir une seule légende qui affiche correctement les formes, les couleurs et les types de lignes (la légende d'interaction (Type, Méthode) est la plus proche de ce que je voudrais, mais elle n'a pas les types de formes/lignes corrects) .

Je sais que si j'utilise scale_xxx_manual et que je spécifie les mêmes étiquettes pour toutes les légendes, elles seront fusionnées, mais je ne souhaite pas avoir à les définir manuellement: s'il existe de nouvelles méthodes ou Types, je ne veux pas avoir à modifier mon code : un désir quelque chose de générique.

Modifier

Comme indiqué dans les réponses ci-dessous, il existe plusieurs façons de faire le travail dans ce cas particulier. Toutes les solutions proposées nécessitent de définir manuellement les types et les formes de ligne de légende, soit à l'aide de scale_xxx_manual function S, soit à l'aide de la fonction guides.

Cependant, les solutions proposées ne fonctionnent toujours pas dans le cas général: par exemple, si j'ajoute un nouveau bloc de données à l'ensemble de données avec une nouvelle méthode "method3", cela ne fonctionne plus, nous devons ajouter manuellement le nouveau légende formes et types de lignes:

y5 <- sin(x - pi / 4)
df5 <- data.frame(x, y = y5, Type = as.factor("sin"), Method = as.factor("method3"))
df.merged <- rbind(df1, df2, df3, df4, df5)
override.shape <- c(16, 17, 16, 17, 16)
override.linetype <- c(1, 1, 3, 3, 4)

g <- ggplot(df.merged, aes(x, y, colour = interaction(Type, Method), linetype = Method, shape = Type)) + geom_line() + geom_point()
g <- g + guides(colour = guide_legend(override.aes = list(shape = override.shape, linetype = override.linetype)))
g <- g + scale_shape(guide = FALSE)
g <- g + scale_linetype(guide = FALSE)
print(g)

Cela donne:

5 curves

Maintenant, la question est: comment générer automatiquement les vecteurs override.shape Et override.linetype?

Notez que la taille du vecteur est 5 car nous avons 5 courbes, alors que le facteur interaction(Type, Method) a la taille 6 (je n'ai pas de données pour la combinaison cos/method3)

44
Ben

Voici la solution dans le cas général:

# Create the data frames
x <- seq(0, 10, by = 0.2)
y1 <- sin(x)
y2 <- cos(x)
y3 <- cos(x + pi / 4)
y4 <- sin(x + pi / 4)
y5 <- sin(x - pi / 4)
df1 <- data.frame(x, y = y1, Type = as.factor("sin"), Method = as.factor("method1"))
df2 <- data.frame(x, y = y2, Type = as.factor("cos"), Method = as.factor("method1"))
df3 <- data.frame(x, y = y3, Type = as.factor("cos"), Method = as.factor("method2"))
df4 <- data.frame(x, y = y4, Type = as.factor("sin"), Method = as.factor("method2"))
df5 <- data.frame(x, y = y5, Type = as.factor("sin"), Method = as.factor("method3"))

# Merge the data frames
df.merged <- rbind(df1, df2, df3, df4, df5)

# Create the interaction
type.method.interaction <- interaction(df.merged$Type, df.merged$Method)

# Compute the number of types and methods
nb.types <- nlevels(df.merged$Type)
nb.methods <- nlevels(df.merged$Method)

# Set the legend title
legend.title <- "My title"

# Initialize the plot
g <- ggplot(df.merged, aes(x,
                           y,
                           colour = type.method.interaction,
                           linetype = type.method.interaction,
                           shape = type.method.interaction)) + geom_line() + geom_point()
# Here is the magic
g <- g + scale_color_discrete(legend.title)
g <- g + scale_linetype_manual(legend.title,
                               values = rep(1:nb.types, nb.methods))
g <- g + scale_shape_manual(legend.title,
                            values = 15 + rep(1:nb.methods, each = nb.types))
# Display the plot
print(g)

Le résultat est le suivant:

The solution

  • Les courbes sinusales sont dessinées sous forme de lignes continues et les courbes cosinus sous forme de lignes pointillées.
  • Les données "method1" utilisent des cercles remplis pour la forme.
  • Les données "method2" utilisent un triangle rempli pour la forme.
  • Les données "method3" utilisent des diamants remplis pour la forme.
  • La légende correspond à la courbe

Pour résumer, les astuces sont les suivantes:

  • Utilisez le Type/Méthode interaction pour toutes les représentations de données (couleur, forme, type de ligne, etc.)
  • Puis définissez manuellement les styles de courbe et de légende avec scale_xxx_manual.
  • scale_xxx_manual vous permet de fournir un vecteur de valeurs plus long que le nombre réel de courbes. Il est donc facile de calculer les valeurs de vecteur de style à partir de la taille des facteurs Type et Méthode.
8
Ben

J'ai eu ce problème l'autre jour. La section R Cookbook sur Legends explique:

Si vous utilisez à la fois la couleur et la forme, vous devez indiquer les deux spécifications de l'échelle. Sinon, il y aura deux deux légendes distinctes.

Dans votre cas, vous avez besoin de spécifications pour shape et linetype.

Modifier

Il était important que les mêmes données créent les formes, les couleurs et les lignes. J'ai combiné votre phase d'interaction en définissant directement la colonne. Au lieu de scale_linetype_discrete pour créer la légende, j’ai utilisé scale_linetype_manual pour spécifier les valeurs car elles prendront quatre valeurs différentes par défaut.

Si vous souhaitez une mise en page détaillée de toutes les formes et types de lignes possibles, cochez this R Graphics site pour afficher tous les identificateurs de numéro:

df.merged$int <- paste(df.merged$Type, df.merged$Method, sep=".")

ggplot(df.merged, aes(x, y, colour = int, linetype=int, shape=int)) +
  geom_line() +
  geom_point() +
  scale_colour_discrete("") +
  scale_linetype_manual("", values=c(1,2,1,2)) +
  scale_shape_manual("", values=c(17,17,16,16))

enter image description here

23
Pierre Lafortune

Utilisez labs() et définissez la même valeur pour toutes les esthétiques définissant l'apparence des zones géographiques.

library('ggplot2')
ggplot(iris) + 
  aes(x = Sepal.Length, y = Sepal.Width, 
      color = Species, linetype = Species, shape = Species) +
  geom_line() +
  geom_point() +
  labs(color  = "Guide name", linetype = "Guide name", shape = "Guide name")

11
lillemets

Il suffit de nommer les deux guides de la même manière. Par exemple:

g+ scale_linetype_manual(name="Guide1",values= c('solid', 'solid', 'dotdash'))+
   scale_colour_manual(name="Guide1", values = c("blue", "green","red"))
10

Le code ci-dessous donne la légende souhaitée, si je comprends votre question, mais je ne suis pas sûr de comprendre le problème de l'étiquette, alors laissez-moi savoir si ce n'est pas ce que vous recherchiez.

p = ggplot(df.merged, aes(x, y, colour=interaction(Type, Method), 
                          linetype=interaction(Type, Method), 
                          shape=interaction(Type, Method))) + 
  geom_line() + 
  geom_point()

p + scale_shape_manual(values=rep(16:17, 2)) +
  scale_linetype_manual(values=rep(c(1,3),each=2))

enter image description here

6
eipi10