web-dev-qa-db-fra.com

ggplot2 étiquette à deux lignes avec expression

J'aimerais écrire une étiquette d'axe sur deux lignes avec une instruction expression(). Cependant, plotmath et expression ne le permettent pas (par exemple, le texte en indice apparaît à l'extrême droite). J'ai trouvé cette discussion circa 2005 environ d'un problème similaire, mais le travail de contournement qu'ils offrent ne se traduit pas par mon application dans ggplot2. Une question récente portait sur une permutation différente des énoncés d’expression multiligne, mais là encore, le travail fourni n’est pas applicable ici.

Exemple:

p <- ggplot(mtcars,aes(x=wt,y=mpg))+
  geom_point()+
  xlab(expression(paste("A long string of text goes here just for the purpose \n of illustrating my point Weight "[reported])))
try(ggsave(plot=p,filename=<some file>,height=4,width=6))

donne une image où l'indice "rapporté" est expulsé vers la droite quand j'aimerais qu'il soit assis à côté du mot précédent .ggplot2 two line label with expression

47
metasequoia

Je pense que c'est un bug. (Ou une conséquence du fait que "les expressions multilignes ne sont pas prises en charge", comme indiqué dans la conversation que vous avez associée).

La solution de contournement à laquelle Gavin Simpson a fait allusion est la suivante:

#For convenience redefine p as the unlabeled plot
p <- ggplot(mtcars,aes(x=wt,y=mpg))+geom_point()

#Use atop to fake a line break
p + xlab(expression(atop("A long string of text for the purpose", paste("of illustrating my point" [reported]))))

enter image description here

Il est possible d'utiliser de vrais sauts de ligne avec des indices. Dans le court exemple ci-dessous, qui a la même forme que votre exemple, l'indice est correctement placé à côté du reste du texte, mais les deux lignes de texte ne sont pas centrées correctement:

p + xlab(expression(paste("line1 \n line2 a" [b])))

enter image description here

Je pense que dans les deux cas, l'indice est mal placé lorsque la ligne supérieure du texte est plus longue que la ligne inférieure du texte. Comparer

p + xlab(expression(paste("abc \n abcd" [reported])))

enter image description here

p + xlab(expression(paste("abc \n ab" [reported])))

enter image description here

L'indice finit toujours par s'aligner juste à droite de l'extrémité droite de la ligne supérieure.

p + xlab(expression(paste("abcdefghijklmnop \n ab" [reported])))

enter image description here

53
Drew Steen

Vous pouvez utiliser cette astuce,

library(gridExtra)
library(grid)

element_custom <- function() {
  structure(list(), class = c("element_custom", "element_text"))
}

element_grob.element_custom <- function(element, label="", ...)  {

  mytheme <- ttheme_minimal(core = list(fg_params = list(parse=TRUE, 
                                                         hjust=0, x=0.1)))
  disect <- strsplit(label, "\\n")[[1]]
  tableGrob(as.matrix(disect), theme=mytheme)
}

# default method is unreliable
heightDetails.gtable <- function(x) sum(x$heights)

ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
  geom_line() + 
  labs(x= "First~line \n italic('and a second') \n integral(f(x)*dx, a, b)")+
  (theme_grey() %+replace% theme(axis.title.x = element_custom()))

 enter image description here

10
baptiste

1) Solution avec cowplot::draw_label()

On pourrait aussi utiliser la fonction d'annotation draw_label() du paquetage cowplot (suggéré dans la discussion this ). Nous pourrions appeler cowplot::draw_label() autant de lignes de texte que nous avons. Lorsque cowplot::draw_label() est utilisé en combinaison avec cowplot::ggdraw(), il peut annoter n'importe où sur le canevas/la feuille avec les coordonnées allant de 0 à 1 (par rapport au canevas entier).

Il faut modifier la position de l'annotation et laisser suffisamment d'espace pour le titre de l'axe personnalisé.

Notez que le paquetage cowplot modifie actuellement le thème par défaut de ggplot. Par conséquent, si nécessaire, utilisez theme_set() après avoir chargé le paquet comme indiqué here .

Notez également que la fonction cowplot::draw_label() utilise ggplot2::annotation_custom() sous le capot. Je mentionnerai plus à ce sujet dans la deuxième partie ci-dessous.

library(ggplot2)
library(cowplot)
#> 
#> Attaching package: 'cowplot'
#> The following object is masked from 'package:ggplot2':
#> 
#>     ggsave

# If needed, revert to default theme (cowplot modifies the theme); 
# theme_set(theme_grey())

p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
# Make enough space for the custom two lines axis title
p <- p + 
  xlab("") + # empty label
  # Tweak the margins (Push the label down by forcing a wider top margin)
  theme(axis.title.x = element_text(size = 10, # also adjust text size if needed
                                    margin = margin(t = 10, r = 0, b = 0, l = 0,
                                                    unit = "mm")))

# The two lines we wish on the plot
line_1 <- "A long string of text for the purpose"
line_2 <- expression(paste("of illustrating my point" [reported]))
# Or avoid paste() (is not actually needed)
# line_2 <- expression("of illustrating my point" [reported])

# Call cowplot::draw_label two times to plot two lines of text
ggdraw(p) + 
  draw_label(line_1, x = 0.55, y = 0.075) + # use relative coordinates for positioning
  draw_label(line_2, x = 0.55, y = 0.025)

Notez que cowplot::draw_label() peut également être utilisé en association avec le paramétrage de l'écrêtage, coord_cartesian(clip = "off"), qui permet de tracer n'importe où sur le canevas. Cette fois, nous n'utilisons plus les coordonnées relatives, mais celles de la parcelle/données (les coordonnées absolues):

# Other two expressions
line_1b <- expression(bolditalic('First line'))
line_2b <- expression(integral(f(x)*dx, a, b))

p + coord_cartesian(clip = "off") + # allows plotting anywhere on the canvas
  draw_label(line_1b, x = 3.5, y = 8.2) + # use absolute coordinates for positioning
  draw_label(line_2b, x = 3.5, y = 6)

Créé le 2019-01-14 par le package reprex (v0.2.1)


2) Solution avec ggplot2::annotation_custom()

Comme mentionné précédemment, cowplot::draw_label() est une enveloppe de ggplot2::annotation_custom(). Ainsi, au lieu de cowplot::draw_label(), nous pourrions utiliser directement ggplot2::annotation_custom() en combinaison avec le paramètre Clipping off - coord_cartesian(clip = "off"), qui est devenu disponible avec la fusion this pull request .

Cependant, cette approche est plus détaillée, avec plus d'arguments de coordonnées et nous devons utiliser grid::textGrob().

# Some other two lines we wish on the plot as OX axis title
line_1c <- expression("Various fonts:" ~ bolditalic("bolditalic") ~ bold("bold") ~ italic("italic"))
line_2c <- expression("this" ~~ sqrt(x, y) ~~ "or this" ~~ sum(x[i], i==1, n) ~~ "math expression")
# the ~~ ads a bit more space than ~ between the expression's components

p + coord_cartesian(clip = "off") +
  annotation_custom(grid::textGrob(line_1c), xmin = 3.5, xmax = 3.5, ymin = 7.3, ymax = 7.3) +
  annotation_custom(grid::textGrob(line_2c), xmin = 3.5, xmax = 3.5, ymin = 5.5, ymax = 5.5)

Créé le 2019-01-14 par le package reprex (v0.2.1)

0
Valentin