ggplot2: divisez la légende en deux colonnes, chacune avec son propre titre
j'ai ces facteurs
require(ggplot2)
names(table(diamonds$cut))
# [1] "Fair" "Good" "Very Good" "Premium" "Ideal"
que je veux diviser visuellement en deux groupes dans la légende (en indiquant aussi le nom du groupe):
"Premier groupe" -> "Juste", "Bon"
et
"Deuxième groupe" -> "Très Bon", "Premium", "Idéal"
à partir de ce tracé
ggplot(diamonds, aes(color, fill=cut)) + geom_bar() +
guides(fill=guide_legend(ncol=2)) +
theme(legend.position="bottom")
je veux obtenir
(notez que "très bon" a glissé dans la deuxième colonne / Groupe)
3 réponses
vous pouvez déplacer la catégorie" très bon " à la deuxième colonne de la légende en ajoutant un facteur fictif niveau et en réglant sa couleur au blanc dans la légende, de sorte qu'il ne peut pas être vu. Dans le code ci-dessous, nous ajoutons un niveau de facteur blanc Entre "bon" et "très bon", donc maintenant nous avons six niveaux. Ensuite, nous utilisons scale_fill_manual
pour définir la couleur de ce nouveau niveau de "blanc". drop=FALSE
force ggplot
pour garder le niveau vide dans la légende. Il pourrait y avoir une façon plus élégante de contrôle où ggplot
lieux de la des valeurs légendaires, mais au moins cela fera le travail.
diamonds$cut = factor(diamonds$cut, levels=c("Fair","Good"," ","Very Good",
"Premium","Ideal"))
ggplot(diamonds, aes(color, fill=cut)) + geom_bar() +
scale_fill_manual(values=c(hcl(seq(15,325,length.out=5), 100, 65)[1:2],
"white",
hcl(seq(15,325,length.out=5), 100, 65)[3:5]),
drop=FALSE) +
guides(fill=guide_legend(ncol=2)) +
theme(legend.position="bottom")
mise à jour: j'espère qu'il y a une meilleure façon d'ajouter des titres à chaque groupe dans la légende, mais la seule option que je peux trouver pour le moment est de recourir à grobs, ce qui me donne toujours un mal de tête. Le code ci-dessous est adapté de la réponse à ce DONC, la question. Il ajoute deux texte grobs, un pour chaque étiquette, mais les étiquettes doivent être positionnés à la main, ce qui est un énorme douleur. Le code de la parcelle doit également être modifié pour créer plus d'espace pour la légende. De plus, même si j'ai désactivé le découpage pour tous les grobs, les étiquettes sont toujours découpées par le Grob legend. Vous pouvez placer les étiquettes en dehors de la zone coupée, mais elles sont trop loin de la légende. J'espère que quelqu'un qui vraiment sait comment travailler avec grobs peut corriger cela et plus généralement améliorer le code ci-dessous (@baptiste, êtes-vous là?).
library(gtable)
p = ggplot(diamonds, aes(color, fill=cut)) + geom_bar() +
scale_fill_manual(values=c(hcl(seq(15,325,length.out=5), 100, 65)[1:2],
"white",
hcl(seq(15,325,length.out=5), 100, 65)[3:5]),
drop=FALSE) +
guides(fill=guide_legend(ncol=2)) +
theme(legend.position=c(0.5,-0.26),
plot.margin=unit(c(1,1,7,1),"lines")) +
labs(fill="")
# Add two text grobs
p = p + annotation_custom(
grob = textGrob(label = "First\nGroup",
hjust = 0.5, gp = gpar(cex = 0.7)),
ymin = -2200, ymax = -2200, xmin = 3.45, xmax = 3.45) +
annotation_custom(
grob = textGrob(label = "Second\nGroup",
hjust = 0.5, gp = gpar(cex = 0.7)),
ymin = -2200, ymax = -2200, xmin = 4.2, xmax = 4.2)
# Override clipping
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip <- "off"
grid.draw(gt)
Et voici le résultat:
ceci ajoute les titres au gtable de la légende. Il utilise la technique de @eipi10 pour déplacer la catégorie" très bon " dans la deuxième colonne de la légende (merci).
la méthode extrait la légende de l'intrigue. Le gtable de la légende peut être manipulé. Ici, une ligne supplémentaire est ajouté à la gtable, et les titres sont ajoutés à la nouvelle ligne. La légende (après un petit réglage) est alors remise dans l'intrigue.
library(ggplot2)
library(gtable)
library(grid)
diamonds$cut = factor(diamonds$cut, levels=c("Fair","Good"," ","Very Good",
"Premium","Ideal"))
p = ggplot(diamonds, aes(color, fill = cut)) +
geom_bar() +
scale_fill_manual(values =
c(hcl(seq(15, 325, length.out = 5), 100, 65)[1:2],
"white",
hcl(seq(15, 325, length.out = 5), 100, 65)[3:5]),
drop = FALSE) +
guides(fill = guide_legend(ncol = 2, title.position = "top")) +
theme(legend.position = "bottom",
legend.key = element_rect(fill = "white"))
# Get the ggplot grob
g = ggplotGrob(p)
# Get the legend
leg = g$grobs[[which(g$layout$name == "guide-box")]]$grobs[[1]]
# Set up the two sub-titles as text grobs
st = lapply(c("First group", "Second group"), function(x) {
textGrob(x, x = 0, just = "left", gp = gpar(cex = 0.8)) } )
# Add a row to the legend gtable to take the legend sub-titles
leg = gtable_add_rows(leg, unit(1, "grobheight", st[[1]]) + unit(0.2, "cm"), pos = 3)
# Add the sub-titles to the new row
leg = gtable_add_grob(leg, st,
t = 4, l = c(2, 6), r = c(4, 8), clip = "off")
# Add a little more space between the two columns
leg$widths[[5]] = unit(.6, "cm")
# Move the legend to the right
leg$vp = viewport(x = unit(.95, "npc"), width = sum(leg$widths), just = "right")
# Put the legend back into the plot
g$grobs[[which(g$layout$name == "guide-box")]] = leg
# Draw the plot
grid.newpage()
grid.draw(g)
suivant l'idée de @eipi10, vous pouvez ajouter le nom des titres comme étiquettes, avec white
valeurs:
diamonds$cut = factor(diamonds$cut, levels=c("Title 1 ","Fair","Good"," ","Title 2","Very Good",
"Premium","Ideal"))
ggplot(diamonds, aes(color, fill=cut)) + geom_bar() +
scale_fill_manual(values=c("white",hcl(seq(15,325,length.out=5), 100, 65)[1:2],
"white","white",
hcl(seq(15,325,length.out=5), 100, 65)[3:5]),
drop=FALSE) +
guides(fill=guide_legend(ncol=2)) +
theme(legend.position="bottom",
legend.key = element_rect(fill=NA),
legend.title=element_blank())
je suis d'introduire des espaces blancs après "Title 1 "
pour séparer les colonnes et d'améliorer la conception, mais il pourrait y avoir une option pour augmenter l'espace.
Le seul problème est que je n'ai aucune idée de comment changer le format de la "titre" étiquettes (j'ai essayé bquote
ou expression
mais il n'a pas travail.)
_____________________________________________________________
selon le graphe que vous tentez, un alignement droit de la légende pourrait être une meilleure alternative, et ce tour semble mieux (IMHO). Il sépare la légende en deux, et utilise l'Espace mieux. Tout ce que vous avez à faire est de changer le ncol
retour 1
et "bottom"
(legend.position
) "right"
:
diamonds$cut = factor(diamonds$cut, levels=c("Title 1","Fair","Good"," ","Title 2","Very Good","Premium","Ideal"))
ggplot(diamonds, aes(color, fill=cut)) + geom_bar() +
scale_fill_manual(values=c("white",hcl(seq(15,325,length.out=5), 100, 65)[1:2],
"white","white",
hcl(seq(15,325,length.out=5), 100, 65)[3:5]),
drop=FALSE) +
guides(fill=guide_legend(ncol=1)) +
theme(legend.position="bottom",
legend.key = element_rect(fill=NA),
legend.title=element_blank())
Dans ce cas, il pourrait être judicieux de laisser le titre dans cette version, en supprimant legend.title=element_blank()