Existe-t-il un moyen de modifier l'espacement entre les éléments de légende dans ggplot2?

120

Existe-t-il un moyen de modifier l'espacement entre les éléments de légende dans ggplot2? J'ai actuellement

legend.position ="top" 

qui produit automatiquement une légende horizontale. Cependant, l'espacement des éléments est très rapproché et je me demande comment les espacer davantage.

survolé
la source
Il serait utile d'avoir une solution actuelle à ce problème maintenant qui optsest dépréciée.
geotheory
Ici: pastebin.com/NnxMiTeH
PatrickT
3
La réponse de Tung, actuellement au bas de ce fil, a une mise à jour de juillet 2018. Des bugs ont été corrigés et des solutions de contournement piratées comme celle de la poubelle ci-dessus ne sont plus nécessaires.
PatrickT

Réponses:

90

ggplot2 v3.0.0publié en juillet 2018 a des options de travail à modifier legend.spacing.x, legend.spacing.yet legend.text.

Exemple: augmenter l'espacement horizontal entre les clés de légende

library(ggplot2)

ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) + 
  geom_bar() +
  coord_flip() +
  scale_fill_brewer("Cyl", palette = "Dark2") +
  theme_minimal(base_size = 14) +
  theme(legend.position = 'top', 
        legend.spacing.x = unit(1.0, 'cm'))

Remarque: si vous souhaitez uniquement élargir l'espacement à droite du texte de la légende, utilisez stringr::str_pad()

Exemple: déplacez les étiquettes des touches de légende vers le bas et augmentez l'espacement vertical

ggplot(mtcars, aes(factor(cyl), fill = factor(cyl))) + 
  geom_bar() +
  coord_flip() +
  scale_fill_brewer("Cyl", palette = "Dark2") +
  theme_minimal(base_size = 14) +
  theme(legend.position = 'top', 
        legend.spacing.x = unit(1.0, 'cm'),
        legend.text = element_text(margin = margin(t = 10))) +
  guides(fill = guide_legend(title = "Cyl",
                             label.position = "bottom",
                             title.position = "left", title.vjust = 1)) 

Exemple: pour scale_fill_xxx&guide_colorbar

ggplot(mtcars, aes(mpg, wt)) +
  geom_point(aes(fill = hp), pch = I(21), size = 5)+
  scale_fill_viridis_c(guide = FALSE) +
  theme_classic(base_size = 14) +
  theme(legend.position = 'top', 
        legend.spacing.x = unit(0.5, 'cm'),
        legend.text = element_text(margin = margin(t = 10))) +
  guides(fill = guide_colorbar(title = "HP",
                               label.position = "bottom",
                               title.position = "left", title.vjust = 1,
                               # draw border around the legend
                               frame.colour = "black",
                               barwidth = 15,
                               barheight = 1.5)) 


Pour les légendes verticales , le réglage legend.key.sizen'augmente que la taille des touches de légende, pas l'espace vertical entre elles

ggplot(mtcars) +
  aes(x = cyl, fill = factor(cyl)) +
  geom_bar() +
  scale_fill_brewer("Cyl", palette = "Dark2") +
  theme_minimal(base_size = 14) +
  theme(legend.key.size = unit(1, "cm"))

Afin d'augmenter la distance entre les touches de légende, une modification de la legend-draw.rfonction est nécessaire. Consultez ce numéro pour plus d'informations

# function to increase vertical spacing between legend keys
# @clauswilke
draw_key_polygon3 <- function(data, params, size) {
  lwd <- min(data$size, min(size) / 4)

  grid::rectGrob(
    width = grid::unit(0.6, "npc"),
    height = grid::unit(0.6, "npc"),
    gp = grid::gpar(
      col = data$colour,
      fill = alpha(data$fill, data$alpha),
      lty = data$linetype,
      lwd = lwd * .pt,
      linejoin = "mitre"
    ))
}

# register new key drawing function, 
# the effect is global & persistent throughout the R session
GeomBar$draw_key = draw_key_polygon3

ggplot(mtcars) +
  aes(x = cyl, fill = factor(cyl)) +
  geom_bar() +
  scale_fill_brewer("Cyl", palette = "Dark2") +
  theme_minimal(base_size = 14) +
  theme(legend.key = element_rect(color = NA, fill = NA),
        legend.key.size = unit(1.5, "cm")) +
  theme(legend.title.align = 0.5)

Tung
la source
3
Merci de l'avoir signalé. C'est une nouvelle fonctionnalité géniale, j'utilisais toujours le dirty-fix de @ user2568648, haha!
Tjebo
1
Votre fonction pour augmenter l'espacement vertical entre les touches de légende est la seule solution que j'ai trouvée qui fonctionne exactement comme je le souhaite et avec une facilité d'utilisation. Merci!
Docconcoct le
69

Je pense que la meilleure option est d'utiliser guide_legenddans guides:

p + guides(fill=guide_legend(
                 keywidth=0.1,
                 keyheight=0.1,
                 default.unit="inch")
      )

Notez l'utilisation de default.unit, pas besoin de charger le gridpackage.

étude
la source
2
Cela nécessite plus de votes positifs, les autres réponses sont obsolètes.
Brandon Bertelsen
8
Cela peut fonctionner pour les légendes horizontales. Cependant, pour ma légende verticale à droite du graphique, cela ne fait qu'augmenter la hauteur de la clé, pas l'espacement entre les clés. Mes clés de légende sont toujours très proches les unes des autres.
Muhsin Zahid Ugur
9
Comme le dit Mushin, cela manque le point, comme avec d'autres réponses, si la légende est VERTICALE, elle étire les clés de légende (par exemple les segments de ligne) sans remplir l'espace entre les touches.
PatrickT
Fonctionne bien avec geom_line et geom_point.
Niels Holst le
45

Un correctif simple que j'utilise pour ajouter de l'espace dans les légendes horizontales, ajoutez simplement des espaces dans les étiquettes (voir l'extrait ci-dessous):

  scale_fill_manual(values=c("red","blue","white"),
                    labels=c("Label of category 1          ",
                             "Label of category 2          ",
                             "Label of category 3"))
user2568648
la source
13
C'est la seule réponse à ce jour qui traite de la question! Cela pourrait être utile en cas de nombreuses entrées: scale_fill_manual(values=values, labels=setNames(paste(labels, " "), entries)).
SaschaH
2
Techniquement pas très agréable, surtout quand vous devez introduire ces espaces dans des niveaux de facteurs, mais c'est la seule solution qui fonctionne.
Patrick Bucher
2
Ou nous pouvons utiliser str_pad pour rendre la vie un peu plus facile
Tung
37

Maintenant que optsc'est obsolète dans le ggplot2package, la fonction themedoit être utilisée à la place:

library(grid) # for unit()
... + theme(legend.key.height=unit(3,"line"))
... + theme(legend.key.width=unit(3,"line"))
Pop
la source
18
Cette solution modifie la hauteur / largeur des boîtes par opposition à l'espacement entre elles.
Berk U.
25

Pour ajouter un espacement entre les entrées d'une légende, ajustez les marges de l'élément de thème legend.text.

Pour ajouter 30 pt d'espace à droite de chaque étiquette de légende (peut être utile pour une légende horizontale):

p + theme(legend.text = element_text(
    margin = margin(r = 30, unit = "pt")))

Pour ajouter 30 pt d'espace à gauche de chaque étiquette de légende (peut être utile pour une légende verticale):

p + theme(legend.text = element_text(
    margin = margin(l = 30, unit = "pt")))

pour un ggplot2objet p. Les mots-clés sont legend.textet margin.

[Note sur la modification: lorsque cette réponse a été publiée pour la première fois, il y avait un bogue. Le bogue a maintenant été corrigé]

jcb
la source
3
Le bogue a maintenant été corrigé, cela devrait être la réponse acceptée.
giocomai
1
Voir également la réponse de Tung pour une mise à jour de juillet 2018 sur ces questions.
PatrickT
17

On dirait que la meilleure approche (en 2018) est d'utiliser legend.key.sizesous l' themeobjet. (par exemple, voir ici ).

#Set-up:
    library(ggplot2)
    library(gridExtra)

    gp <- ggplot(data = mtcars, aes(mpg, cyl, colour = factor(cyl))) +
        geom_point()

C'est très simple si vous utilisez theme_bw():

  gpbw <- gp + theme_bw()

#Change spacing size:

  g1bw <- gpbw + theme(legend.key.size = unit(0, 'lines'))
  g2bw <- gpbw + theme(legend.key.size = unit(1.5, 'lines'))
  g3bw <- gpbw + theme(legend.key.size = unit(3, 'lines'))

  grid.arrange(g1bw,g2bw,g3bw,nrow=3)

entrez la description de l'image ici

Cependant, cela ne fonctionne pas très bien autrement (par exemple, si vous avez besoin de l'arrière-plan gris sur votre symbole de légende):

  g1 <- gp + theme(legend.key.size = unit(0, 'lines'))
  g2 <- gp + theme(legend.key.size = unit(1.5, 'lines'))
  g3 <- gp + theme(legend.key.size = unit(3, 'lines'))

  grid.arrange(g1,g2,g3,nrow=3)

#Notice that the legend symbol squares get bigger (that's what legend.key.size does). 

#Let's [indirectly] "control" that, too:
  gp2 <- g3
  g4 <- gp2 + theme(legend.key = element_rect(size = 1))
  g5 <- gp2 + theme(legend.key = element_rect(size = 3))
  g6 <- gp2 + theme(legend.key = element_rect(size = 10))

  grid.arrange(g4,g5,g6,nrow=3)   #see picture below, left

Notez que les carrés blancs commencent à bloquer le titre de la légende (et éventuellement le graphique lui-même si nous continuons d'augmenter la valeur).

  #This shows you why:
    gt <- gp2 + theme(legend.key = element_rect(size = 10,color = 'yellow' ))

entrez la description de l'image ici

Je n'ai pas encore trouvé de solution pour résoudre le problème ci-dessus ... Faites-moi savoir dans les commentaires si vous avez une idée, et je mettrai à jour en conséquence!

  • Je me demande s'il existe un moyen de recouvrir les choses en utilisant $layers...
theforestecologist
la source
Make the legend.keytransparent:theme(legend.key = element_rect(size = 30,color=alpha("transparent",0)))
ukosteopathe
1
c'était la réponse la plus simple et la plus facile à utiliser imo
Blacklivesmatter
14

D'après le travail de Koshke sur ggplot2 et son blog (blog de Koshke )

... + theme(legend.key.height=unit(3,"line")) # Change 3 to X
... + theme(legend.key.width=unit(3,"line")) # Change 3 to X

Tapez theme_get()dans la console pour voir les autres attributs de légende modifiables.

Brandon Bertelsen
la source
12
Merci pour la suggestion et le lien vers le blog de Koshke! Malheureusement, cela semble changer la taille des boîtes mais pas l'espacement entre les éléments.
survolé le
Vous pourrez peut-être le "simuler" avec un type de grob superposé. Mais je ne pense pas qu'il y ait un moyen d'obtenir un espacement supplémentaire à l'intérieur de la légende. C'est la seule mention que j'ai pu trouver dans la liste de diffusion de ggplot2
Brandon Bertelsen
2
Je peux l'utiliser pour augmenter l'espacement entre les légendes avec succès. L'utilisation de nombres négatifs a aidé à réduire l'espacement entre les légendes.
Nova
5

Utilisez l'un de ces

legend.spacing = unit(1,"cm")
legend.spacing.x = unit(1,"cm")
legend.spacing.y = unit(1,"cm")
MaazKhan47
la source