5

I'm using the code below to generate a simple box plot in ggplot2:

# Libs data
data("mtcars"); require(ggplot2); require(ggthemes)
# Chart
ggplot(data = mtcars) +
  geom_boxplot(aes(y = wt, x = as.factor(am)),
               fill = "gray87") +
  xlab("AM") +
  ylab("WT") +
  theme_gdocs() +
  ggtitle("WT by AM") +
  theme(axis.title.y = element_text(angle = 90),
        axis.ticks = element_line(colour = "black", linetype = "solid",
                                  size = 0.5),
        panel.grid = element_line(colour = "gray"))

The generated chart is fairly straightforward: First chart

Task

I would like to add a subtitle to my chart and have some control over how it's rendered. I'm following this discussion and with use of the code:

# Chart
ggplot(data = mtcars) +
  geom_boxplot(aes(y = wt, x = as.factor(am)),
               fill = "gray87") +
  xlab("AM") +
  ylab("WT") +
  theme_gdocs() +
  ggtitle(expression(atop("WT by AM", 
                          atop(italic("Some crucial note that has to be here"), "")))) +
  theme(axis.title.y = element_text(angle = 90),
        axis.ticks = element_line(colour = "black", linetype = "solid",
                                  size = 0.5),
        panel.grid = element_line(colour = "gray"))

I get the following chart: second attempt


This looks really bad, and I would like to change a few things:

  1. Make both subtitle and the title left-justified
  2. Reduce the white space between the two lines
  3. Keep the font bold

Attempts

I tried different things, like for instance the code below:

ggplot(data = mtcars) +
  geom_boxplot(aes(y = wt, x = as.factor(am)),
               fill = "gray87") +
  xlab("AM") +
  ylab("WT") +
  theme_gdocs() +
  ggtitle(expression(atop("WT by AM", 
                          atop(italic("Stupid note"), "")))) +
  theme(axis.title.y = element_text(angle = 90),
        axis.ticks = element_line(colour = "black", linetype = "solid",
                                  size = 0.5),
        panel.grid = element_line(colour = "gray"),
        plot.title = element_text(size = 16, colour = "black", hjust = -1))

but it hides the title entirely:

missing title

Community
  • 1
  • 1
Konrad
  • 17,740
  • 16
  • 106
  • 167
  • 1
    `hjust` must be between 0 and 1. Also, do you need the italics? Otherwise, you could just use `ggtitle("WT by AM\nSome crucial note that has to be here")`. – Roland Dec 04 '15 at 12:37
  • @Roland Thanks for showing the interest. I know I could break lines with `\n` as [discussed here](http://stackoverflow.com/questions/16074440/r-ggplot2-center-align-a-multi-line-title) but I'm more interested in taming the `expression` so I can force it to behave. I know it's rather petty thing. – Konrad Dec 04 '15 at 12:39
  • 1
    I don't think you can combine `atop` with left alignment. Good luck. – Roland Dec 04 '15 at 12:41
  • @Roland Thanks, we will see how it goes. I would hope that `expression` is quite flexible. At the end, I wouldn't say that it is such an odd request. BTW, I created a presentable version of the chart using `hjust = 0.5` and putting the title in the centre. Having said that I would prefer to stay close to what is offered when using `theme_gdocs()` as I like it. – Konrad Dec 04 '15 at 12:44
  • `atop` is for creating mathematical expressions. It's supposed to have central alignment. It's called plot**math** for a reason. – Roland Dec 04 '15 at 12:49
  • Solution that would get me close to the desired results but without making use of the *plotmath* would be fine. Speaking of which, [this solution](http://stackoverflow.com/a/32281523/1655567) is not too far off with respect to achieving nice justification. – Konrad Dec 04 '15 at 12:53
  • can you be more specific re: "reduce the white space between the two lines"? Are you talking about the lines of text (title, subtitle)? Or lines of the boxplot (and which ones)? Also, how are you passing the expression into `atop`, because I could only make it pass literal text -- for example, if I put `atop(eval(foo))` it would literally put "eval(foo)" in the title – C8H10N4O2 Dec 04 '15 at 14:35

3 Answers3

4

There is a new version of ggplot2 (2.1.0.9000+) currently on Github that solves your problem. For more information, see Bob Rudis' vignette.

devtools::install_github("hadley/ggplot2")  # Until the new version is available on CRAN
library(ggplot2)
library(ggthemes)  # Only necessary because the OP used theme_gdocs()

ggplot(data = mtcars) +
  geom_boxplot(aes(y = wt, x = as.factor(am)), fill = "gray87") +
  xlab("AM") +
  ylab("WT") +
  theme_gdocs() +
  ggtitle("WT by AM", subtitle = "pearl of wisdom") +  # subtitle is a new argument. Both are now left-justified by default
  theme(plot.title=element_text(margin=margin(b=0), size = 20), plot.subtitle=element_text(margin=margin(t=5, b = 10)))  # Changing the size and margins of the title and subtitles to give the OP some options.

Title and Subtitle Image

3

From the "it's stupid but it works" file, you can add spaces to the right of center to force left alignment. The right number of spaces could be determined using math, but I couldn't see how to pass a string variable back into atop.

# Chart
ggplot(data = mtcars) +
  geom_boxplot(aes(y = wt, x = as.factor(am)), fill = "gray87") +
  xlab("AM") + ylab("WT") + theme_gdocs() +
  ggtitle(expression(atop("WT by AM                            ", 
                          atop(italic("Some crucial note that has to be here"), "")))) +
  theme(axis.title.y = element_text(angle = 90),
        axis.ticks = element_line(colour = "black", linetype = "solid", size = 0.5),
        panel.grid = element_line(colour = "gray"))

enter image description here

C8H10N4O2
  • 18,312
  • 8
  • 98
  • 134
  • Thanks very much for showing the interest and your answer. It's a dirty trick but it works. – Konrad Dec 04 '15 at 15:22
1

Does it have to use the "expression" command? I was doing this in ggplot2, but I imagine this would work for ggplot since they're both using plotmath.

You can use bquote and atop to add spaces based upon the length of the difference in strings. You can source things from the environment via .() in bquote's paste.

bquote(atop(
       paste("WT by AM", .(paste0(replicate(nchar("Some Crucial Note that Has to Be Here") - nchar("WT by AM"), " "), collapse = ""), 
       paste("Some Crucial Note that Has to Be Here")
            ) 
       )

As for adjusting for the different sizes of the spaces (due to font size), I'd just multiply the expression for length in replicate by a number (use floor or ceiling if you get a fraction).

EDIT: However, the characters " " and "a" have different lengths when plotted, so even having the # of spaces as the difference in string lengths isn't perfect.

A Duv
  • 393
  • 1
  • 17