Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

\newline support #11

Open
DavisBrian opened this issue Feb 19, 2018 · 12 comments
Open

\newline support #11

DavisBrian opened this issue Feb 19, 2018 · 12 comments
Assignees

Comments

@DavisBrian
Copy link

Thanks for the great package it has helped me immensely. One thing I quite haven’t figured out is how to add a \newline or \n in a plot. I frequently have long facet labels and/or legend labels that need both line breaks and superscripting. I noticed in issue #8 and #10 it is suggested to use \n to break the line but this does not appear to actually work as suggested.

@caijun
Copy link

caijun commented May 5, 2018

I also frequently have the same need of line breaks.

@caijun
Copy link

caijun commented May 11, 2018

I think this feature is related to the line break(\n) support in plotmath expression, rather than latex2exp itself, as latex2exp just converts the LaTeX into corresponding plotmath expression. From the question answered by Uwe Ligges, who is a member of the R Core,

http://r.789695.n4.nabble.com/newline-in-plotmath-expressions-td795815.html

we know directly using \n in plotmath expression cannot achieve the line break effect. To break the line, two solutions can be considered. One is to break the plotmath expression into two individual lines, as suggested in the R help question. The other is using the atop function.

https://stackoverflow.com/questions/29112697/adding-a-newline-in-a-substitute-expression

@kmiddleton
Copy link

Here is a workaround to get TeX() to work with atop(). It's not pretty, but it does work.

Use TeX() to generate the expressions:

> TeX("Top Label^2")
expression(`Top Label^2` = paste("Top Label", phantom()^{
    paste("2")
}, ""))
> TeX("Bottom Label_{sub}")
expression(`Bottom Label_{sub}` = paste("Bottom Label", phantom()[{
    paste("sub")
}]))

And then paste everything enclosed in expression() into expression(atop()):

tibble(x = 1:10, y = rnorm(10)) %>% 
  ggplot(aes(x, y)) +
  geom_point() +
  labs(y = expression(
    atop(`Top Label^2` = paste("Top Label", phantom()^{paste("2")}, ""),
         `Bottom Label_{sub}` = paste("Bottom Label", phantom()[{paste("sub")}]))))

If there were an option for TeX() to not wrap its output in expression() (or a separate function to do so), then I think this approach might work for the expression(atop()) approach to multi-line axis labels.

Is there a way to return Top Label^2 = paste("Top Label", phantom()^{paste("2")}, "") from a function?

@jerlich
Copy link

jerlich commented Nov 26, 2018

I have used a workaround of using cowplot::draw_label. You can put latex text anywhere you want. but it does require a bit of fiddling to get the position just right.

@KJByron
Copy link

KJByron commented Jan 24, 2020

also would like to see TeX support new lines and have the option to return text instead of an expression
@kmiddleton's solution works well until some of the text has to be passed in as variables

here's a workaround using glue and plotmath

x_top <- "Top~Label^2"
x_bot <- "Bottom~Label[sub]" 
tibble(x = 1:10, y = rnorm(10)) %>% 
  ggplot(aes(x, y)) +
  geom_point() +
  labs(y = parse(text = glue::glue("atop({x_top}, fixed~text~{x_bot})")))

but what if I wanted 3 or more lines of code? - yuck...
using TeX would be so much cleaner!

I see there is an output argument in TeX, but it currently doesn't seem to do anything

a1 <- TeX("a", output = "expression")
a2 <- TeX("a", output = "text")
identical(a1, a2)
# [1] TRUE

@danote
Copy link

danote commented Aug 18, 2020

A somewhat easier/straightforward variation on @kmiddleton 's workaround is to use $\\overset{x}{y}$ as in latex2exp's homepage examples.

@caimiao0714
Copy link

A somewhat easier/straightforward variation on @kmiddleton 's workaround is to use $\\overset{x}{y}$ as in latex2exp's homepage examples.

Thank you! This work around works for me, is there a good workaround if I need 2 linebreaks (three lines)?

@danote
Copy link

danote commented Oct 30, 2020

A somewhat easier/straightforward variation on @kmiddleton 's workaround is to use $\\overset{x}{y}$ as in latex2exp's homepage examples.

Thank you! This work around works for me, is there a good workaround if I need 2 linebreaks (three lines)?

I'm glad it was helpful. I've never had to use 3 lines, but perhaps it is possible to string together oversets?

@stefano-meschiari stefano-meschiari self-assigned this Jan 25, 2022
@bishun945
Copy link

A somewhat easier/straightforward variation on @kmiddleton 's workaround is to use $\\overset{x}{y}$ as in latex2exp's homepage examples.

Thank you! This work around works for me, is there a good workaround if I need 2 linebreaks (three lines)?

Try ggplot() + xlab(latex2exp::TeX("$\\overset{\\overset{}{x}}{\\overset{y}{z}}$"))

@stefano-meschiari
Copy link
Owner

In addition to that, if you need to do more than two lines (or one of the lines contains a "tall" command, e.g. \int, that you want to render in full size), you need to wrap the content of each \overset in \normalsize. For example,

plot(TeX(r"(\overset{\normalsize{First line: $\int_a^b x dx$}}{\overset{\normalsize{Second line: $\prod_{i=1}^\infty A_i$}}{\normalsize{Third line: x}}$})"))

will produce
image

A future version of latex2exp will do this automatically when it detects line breaks, but for now, it should work fine.

@glocke-senda
Copy link

I wish some things were simpler. Here's a function that splits an arbitrary number of lines, including 1.

set.seed(50389082) # least solution to Archimedes' cattle problem. good to know.
latex_lines <- function(each_line) { # spread each entry in each_line onto a different line using overset, wrapping each line in normalsize
  if ("character" != class(each_line)) {
    stop("latex_lines expects a character vector")
  }
  ret <- paste0("\\normalsize{", each_line[1], "}")
  while(0 != length(each_line <- tail(each_line, n=-1))) {
    ret <- paste0("\\overset{", ret, "}{\\normalsize{", each_line[1],"}}")
  }
  return(ret)
}
tibble(x=1:10) %>% 
  dplyr::mutate(
    y=runif(10, max=x),
    lab0 = paste0("\\overset{\\overset{\\normalsize{$\\chi$ == ", x, "}}{\\normalsize{123}}}{\\normalsize{456}}"),
    lab = latex2exp::TeX(lab0, output = 'character'),
    brute_force = paste0("χ = ", x, "\n123\n456")
  ) %>% 
  dplyr::rowwise() %>% 
  dplyr::mutate(
    lab00 = latex_lines(
      c(paste0("$\\chi$ == ", x),
        123,
        456
      )
    ),
    lab2 = latex2exp::TeX(lab00, output = 'character')
  ) %>% 
  ggplot(aes(x=x, y=y, label=lab2)) +
  geom_point() +
  geom_text(aes(y=y+1), parse=T, hjust=0) ## set parse=F to plot the brute_force label
  

image

lab1 and lab2 produce identical results. brute_force gives the result I actually want (each line left justified).

Needless to say, hjust=0 isn't producing the desired result of left justifying the three lines. If you know of latex that will left justify the overset, please let me know. Also, the last line is separated a bit extra, which afaict means it's not possible to get a publication quality image using overset. The brute force solution looks best in this case, but if you had non-trivial latex expression there would be no brute force solution. If you really need a publication quality image, separate each line into a different geom and "hard code" the line breaks by calculating a different y coordinate.

Hopefully the actual solution our fearless leaders introduce will respect hjust while it adds lines...

@ggrothendieck
Copy link

atop and overset center the text. A left-justified version would be desirable, in addition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests