3

When making plots using ggplot2, how can I wrap the title text to fit margins that are relative to the plot's entire width?

library(ggplot2)
library(stringr)

my_title <- c("reltively long sentences that normally isn't appropriate as a title but it is what it is")

ggplot(ToothGrowth, aes(x = factor(dose), y = len)) + 
  geom_boxplot() +
  labs(title = my_title) +
  theme(plot.title = element_text(hjust = 0.5))

plot_1

I'm looking to get something like this

plot_2

Can this be achieved?

Emman
  • 3,695
  • 2
  • 20
  • 44
  • Can I ask what you mean precisely when you say you're looking to solve to problem in a more exact way? – teunbrand Dec 27 '20 at 22:42
  • 1
    Sure, sorry for being unclear. (1) It's critical to me that the margins (right and left) will be equal in length (from each edge). Your answer below is great, but you can see here that the margins aren't equal: https://i.stack.imgur.com/ShzQw.png. (2) Once issue (1) is figured out, I strongly need to be able to specify the margins' length in percent. Here in the post I gave an example of 25%, but hopefully I could simply set the number and tweak the margins. – Emman Dec 28 '20 at 07:18
  • Thanks that helps. With regards to issue (2), you could tweak the `width = unit(x, "npc")` argument in my answer below to `x = 1 - 2 * desired_fraction`. With regards to (1), other than using the `plot.title.position` mentioned in the comment, I don't think there are precise text shaping packages that could adjust the letter spacing so a line spans an exact width. This is also tricky in MS Word or Adobe InDesign. – teunbrand Dec 28 '20 at 09:57
  • Sure, that's reasonable, I don't expect it to space the letters to fit the margins. I just want a word to go down to the next line (i.e., wrap the text) if it overrides the margin. But even with `plot.title.position = "plot"` it doesn't seem to have equal length in margins (from plot's edges). I've commented on your answer. – Emman Dec 28 '20 at 10:31

1 Answers1

8

Not a 100% satisfactory answer to the question but it might still be helpful. Instead of aligning to the entire plot's width, we can align to the panel's width with ggtext::element_textbox(). You can vary the margin argument depending on the size of the title, unit(15, "pt") seemed to work in this particular case.

library(ggplot2)
#> Warning: package 'ggplot2' was built under R version 4.0.2
library(ggtext)
#> Warning: package 'ggtext' was built under R version 4.0.3

my_title <- c("reltively long sentences that normally isn't appropriate as a title but it is what it is")

ggplot(ToothGrowth, aes(x = factor(dose), y = len)) + 
  geom_boxplot() +
  labs(title = my_title) +
  theme(
    plot.title = element_textbox(hjust = 0.5,
                                 width = unit(0.5, "npc"),
                                 margin = margin(b = 15))
  )

Created on 2020-12-25 by the reprex package (v0.3.0)

EDIT: Example with plot.title.position = "plot". If you set element_textbox(..., halign = 0.5), then the distances from the text to the borders is equal, but this will center-align the text.

ggplot(ToothGrowth, aes(x = factor(dose), y = len)) + 
  geom_boxplot() +
  labs(title = my_title) +
  theme(
    plot.title = element_textbox(hjust = 0.5,
                                 width = unit(0.5, "npc"),
                                 margin = margin(b = 15)),
    plot.title.position = "plot"
  )

Created on 2020-12-28 by the reprex package (v0.3.0)

teunbrand
  • 33,645
  • 4
  • 37
  • 63
  • Note, you can also use this method to align to entire width by setting `plot.title.position = "plot"` in the theme. – teunbrand Dec 25 '20 at 00:49
  • Could you please provide an example for code and plot for using this with `plot.title.position = "plot"`? Following your advice I tried running such code but it didn't seem to have equal margin lengths. – Emman Dec 28 '20 at 10:29
  • Thank you for the edit. Yes, having `halign = 0.5` centers the text and keeps the margins equal, and is truly what I was looking for! – Emman Dec 29 '20 at 07:01
  • @Emman, if teunbrand answered your question, you should mark it as the best answer. This will give them credit for providing a correct answer and help others with the same problem know that there is a correct answer to this question. – AColeman Dec 29 '20 at 16:32