ggplot2 two-line label with expression

ggplot2 axis labels line break
ggplot title
ggplot legend labels
ggplot add legend manually
ggplot legend multiple lines
ggplot label lines
ggplot axis label position
r line break axis label

I'd like to write an axis label over two lines with an expression() statement. However, plotmath and expression won't allow this (e.g. subscripted text appears on the far right). I found this discussion circa 2005 of a similar issue but the work around that they offer doesn't translate to my application in ggplot2. A recent question addressed a different permutation of multi-line expression statements, but again the work around provided doesn't apply here.

Example:

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))

yields an image where subscript "reported" is kicked out to the right when I'd like it to sit next to the previous word.

I think this is a bug. (Or a consequence of the fact that "multi-line expressions are not supported", as stated in the conversation you linked to).

The workaround that Gavin Simpson alluded to is:

#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]))))

It is possible to use true line breaks with subscripts. In the short example below, which has the same form as your example, the subscript is correctly placed adjacent to the rest of the text but the two lines of text are not centered correctly:

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

I think that in both cases, the subscript is placed wrong when the upper line of text is longer than the lower line of text. Compare

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

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

The subscript always ends up aligned just to the right of the right end of the upper line.

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

properly formatting a two-line caption in ggplot2 · Issue #2848 , properly formatting a two-line caption in ggplot2 #2848 When an expression is entered, the concatenated caption gets completely mangled. custom function to add labels to the plot plot_maker <- function(xlab = NULL,  Stack Overflow for Teams is a private, secure spot for you and your coworkers to find and share information. Learn more How to make a multi-line x axis title with mathematical expressions in ggplot2 [duplicate]

You could use this trick,

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()))

Line Breaks Between Words in Axis Labels in ggplot in R, We can use regular expressions to add line breaks to the factor levels by Just a note: if you're not using ggplot, the multi-line axis labels might  When an expression is entered, the concatenated caption gets completely mangled. EDIT: In case you have a different solution which achieves the same thing (if the user-provided caption is NULL, then the default one-line expression is printed as a caption, otherwise a two-line expression printed as a caption), I am also open to that.

1) Solution with cowplot::draw_label()

One could also use the annotation function draw_label() from the package cowplot (suggested in this discussion). We could call cowplot::draw_label() as many lines of text we have. When cowplot::draw_label() is used in combination with cowplot::ggdraw(), it can annotate anywhere on the canvas/sheet with the coordinates ranging from 0 to 1 (relative to the entire canvas).

One needs to tweak the annotation position and make enough space for the custom axis title.

Note that the cowplot package currently alters the default ggplot theme, therefore, if needed, use theme_set() after loading the package as mentioned here.

Note also that the function cowplot::draw_label() uses ggplot2::annotation_custom() under the hood. I'll mention more about this in the second part below.

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)

Note that, cowplot::draw_label() can also be used in combination with setting the clipping off, coord_cartesian(clip = "off"), which allows plotting anywhere on the canvas. This time we do not use the relative coordinates anymore, but the ones from the plot/data (the absolute coordinates):

# 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)

Created on 2019-01-14 by the reprex package (v0.2.1)


2) Solution with ggplot2::annotation_custom()

As mentioned, cowplot::draw_label() is a wrapper of ggplot2::annotation_custom(). So, instead of cowplot::draw_label(), we could use directly ggplot2::annotation_custom() in combination with setting the clipping off - coord_cartesian(clip = "off"), which became available with merging this pull request.

However, this approach is more verbose, with more coordinate arguments and we need to employ 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)

Created on 2019-01-14 by the reprex package (v0.2.1)

Legend guide, keyheight = NULL, direction = NULL, default.unit = "line", override.aes = list(), nrow = NULL, ncol = NULL, A character string or expression indicating a title of guide. A numeric specifying horizontal justification of the label text. positive integer less than 99 that specifies the order of this guide among multiple guides. Yesterday, I was trying to put some finishing touches on a figure I made in ggplot2 that visualizes some simulation results. The plot features several panels using facet_grid(), and uses colors to distinguish between different regression models that were fit to the simulated data. I wanted to label certain axes and panel names using the Greek letters I had used as parameter notation, and I

The package ggtext offers a different option, by allowing for HTML tags to format/customise labels and text.

library(ggtext)
ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  xlab("A long string of text goes here just for the purpose<br>of illustrating my point Weight<sub>reported</sub>") +
  theme(axis.title.x = element_markdown())

Text, If TRUE , the labels will be parsed into expressions and displayed as described in ?plotmath . label.padding. Amount of padding around label. Defaults to 0.25 lines. label.r There are two special alignments: "inward" and "outward" . Inward​  ggplot2 two-line label with expression (2) I think this is a bug. (Or a consequence of the fact that "multi-line expressions are not supported", as stated in the conversation you linked to). The workaround that Gavin Simpson alluded to is:

Plotting with ggplot: : adding titles and axis names – Environmental , This page provides help for adding titles, legends and axis labels. If you have a particulary long title that would work better on two lines, use  Sometimes when plotting factor variables in R, the graphics can look pretty messy thanks to long factor levels. If the level attributes have multiple words, there is an easy fix to this that often makes the axis labels look much cleaner.Without Line Br

ggplot2 - Curtis Kephart, ggplot(data, aes(x=Xvar, y=Yvar, colour=ColorVar) + Breaks and labels are straitforward (just make sure they correspond). For values expression( paste( Text geoms are useful for labeling plots. They can be used by themselves as scatterplots or in cobination with other geoms, for example, for labeling points or for annotating the height of bars. geom_text() adds only text to the plot. geom_label() draws a rectangle behind the text, making it easier to read.

Titles (ggplot2), bp + ggtitle("Plant growth") ## Equivalent to # bp + labs(title="Plant growth") # If the title is long, it can be split into multiple lines with \n bp + ggtitle("Plant growth  Re: ggplot2: expression() in legend labels? Hmm, that's my fault when composing this mail, but the problem was really encountered at that time. Nevertheless, neither can I reproduce the problem now, perhaps I just made another mistake at that time.

Comments
  • Why do you need an expression here (i.e. plotmath)? If it is just a strong, pop a \n in to the character vector.
  • Perhaps I don't understand your suggestion, but I do include \n in the label. I need expression to use certain symbols in my application (e.g. subscript and degree).
  • Right, your example doesn't need expression(), the simple paste() would do. See the atop() operator in ?plotmath
  • Nice demonstration. Not sure what to do about the subscript, but the reason the start of the second line shifts slightly to the right is because there is an extra space after the newline character. Entering p+xlab(expression(paste("abcdefghijklmnop \nab" [reported]))) instead of p+xlab(expression(paste("abcdefghijklmnop \n ab" [reported]))) at least ensures that both lines start at the same position...though admittedly this does not get around the unsightly gap before the subscript.
  • would be very useful for me now… but doesn't worth with R 3.4.0 and ggplot2_2.2.1 :(