48

I would like to left align the title in a plot like this

ggplot(data = economics, aes(x = date, y = unemploy)) +
 geom_line() +
 ggtitle("Unemployment in USA between 1967 and 2007") +
 xlab("") +
 ylab("Unemployed [thousands]")

basic ggplot2 plot

First attempt

ggplot(data = economics, aes(x = date, y = unemploy)) + geom_line() +
 ggtitle("Unemployment in USA for some years") +
 xlab("") +
 ylab("Unemployed [thousands]") +
 theme(plot.title = element_text(hjust = -0.45, vjust=2.12)))

enter image description here

Yay success! But wait... there's more... now I want to change the title to something else.

ggplot(data = economics, aes(x = date, y = unemploy)) +
 geom_line() +
 ggtitle("Unemployment in USA between 1967 and 2007") +
 xlab("") +
 ylab("Unemployed [thousands]") +
 theme(plot.title = element_text(hjust = -0.45, vjust=2.12))

new title

So now I need to adjust hjust... :(

The question

How can I make the title left justified (a couple of pixels left of the y axis label or so) over and over again without messing with the hjust value? Or what is the relationship between hjust and the length of the string?

I have tried to annotate manually according to this question, but then I got only the title, and nothing else for some reason - and an error.

Thank you!

Community
  • 1
  • 1
bytesinflight
  • 1,624
  • 2
  • 17
  • 28
  • possible duplicate of [How to adjust title position in ggplot2](http://stackoverflow.com/questions/19621512/how-to-adjust-title-position-in-ggplot2) –  May 12 '15 at 07:04
  • 1
    @user3710546 - these two questions are NOT duplicates - this question is asking about the left border - the other question just wants a left justify. – MatthewR Feb 02 '17 at 05:06

6 Answers6

64

This question refers to this github tidyverse/ggplot2 solved issue: https://github.com/tidyverse/ggplot2/issues/3252

And it is implemented in ggplot2 (development version): https://github.com/tidyverse/ggplot2/blob/15263f7580d6b5100989f7c1da5d2f5255e480f9/NEWS.md

Themes have gained two new parameters, plot.title.position and plot.caption.position, that can be used to customize how plot title/subtitle and plot caption are positioned relative to the overall plot (@clauswilke, #3252).

To follow your example as a reprex:

# First install the development version from GitHub:
#install.packages("devtools") #If required
#devtools::install_github("tidyverse/ggplot2")

library(ggplot2)
packageVersion("ggplot2")
#> [1] '3.2.1.9000'

ggplot(data = economics, aes(x = date, y = unemploy)) + 
  geom_line() +
  labs(x=NULL,
       y="Unemployed [thousands]",
       title = "Unemployment in USA for some years",
       subtitle = "A subtitle possibly",
       caption  = "NOTE: Maybe a caption too in italics.") +
  theme(plot.caption = element_text(hjust = 0, face= "italic"), #Default is hjust=1
        plot.title.position = "plot", #NEW parameter. Apply for subtitle too.
        plot.caption.position =  "plot") #NEW parameter

Created on 2019-09-04 by the reprex package (v0.3.0)

CamiloEr
  • 1,112
  • 1
  • 9
  • 12
32

Until someone comes up with a better solution, one way would be something like

library(ggplot2)
library(grid)
library(gridExtra)
p <- ggplot(data = economics, aes(x = date, y = unemploy)) +
    geom_line() +
    labs(x = NULL, y = "Unemployed [thousands]", title = NULL)

title.grob <- textGrob(
    label = "Unemployment in USA for some years",
    x = unit(0, "lines"), 
    y = unit(0, "lines"),
    hjust = 0, vjust = 0,
    gp = gpar(fontsize = 16))

p1 <- arrangeGrob(p, top = title.grob)
grid.draw(p1)

enter image description here

baptiste
  • 75,767
  • 19
  • 198
  • 294
konvas
  • 14,126
  • 2
  • 40
  • 46
  • 1
    Thanks! Very nice! If you had not said "until someone comes up with a better solution" I might have accepted this right off the bat. :) Thanks for the quick reply too! – bytesinflight Aug 20 '14 at 10:58
  • @konvas How would I go moving the title within the plot so that it's in the upper right hand corner? The 'hjust' works but not the 'vjust' part for me. Any suggestions are appreciated! Thanks – Meli Jun 28 '16 at 14:11
  • Would you count [this](https://stackoverflow.com/a/47625672/4975218) as a better solution? – Claus Wilke Dec 04 '17 at 02:27
  • @ClausWilke how? it's exactly the same idea with IMO unnecessary new names ("ggdraw", "draw_text"). Furthermore, wrapping the whole thing into an invisible ggplot2 just to add one annotation seems overkill and inefficient in this case. – baptiste Dec 04 '17 at 05:48
  • @babtiste Leaving aside whether this is a good approach here, I'd like to provide a defense for the `draw_*` functions. They are wrappers around `geom_*` that (i) don't require data frames as input; (ii) don't do aesthetic mapping; (iii) don't inherit aesthetic mapping. They're useful for quick one-off annotations. You could do the same thing with geoms but will usually require at least twice as much code. – Claus Wilke Dec 04 '17 at 16:53
  • And as to `ggdraw`, I've found it useful to be able to place annotations on a global coordinate system that spans the entire plot area. This is easy in base R but can't be done in ggplot2. You could do this with grid, but I like the convenience of being able to use all ggplot2 features in this global coordinate system. – Claus Wilke Dec 04 '17 at 16:55
14

You can manually adjust the layout of the ggplot output. First, we set up the basic plot:

library(ggplot2)
p <- ggplot(data = economics, aes(x = date, y = unemploy)) +
 geom_line() +
 labs(title = "Unemployment in USA between 1967 and 2007", 
      x = NULL, y = "Unemployed [thousands]")

We can now convert the ggplot object into a gtable object, and inspect the layout of the elements in the plot. Notice that the title is in the fourth column of the grid, the same column as the main panel.

g <- ggplotGrob(p)
g$layout
#    t l  b r  z clip       name
# 17 1 1 10 7  0   on background
# 1  5 3  5 3  5  off     spacer
# 2  6 3  6 3  7  off     axis-l
# 3  7 3  7 3  3  off     spacer
# 4  5 4  5 4  6  off     axis-t
# 5  6 4  6 4  1   on      panel
# 6  7 4  7 4  9  off     axis-b
# 7  5 5  5 5  4  off     spacer
# 8  6 5  6 5  8  off     axis-r
# 9  7 5  7 5  2  off     spacer
# 10 4 4  4 4 10  off     xlab-t
# 11 8 4  8 4 11  off     xlab-b
# 12 6 2  6 2 12  off     ylab-l
# 13 6 6  6 6 13  off     ylab-r
# 14 3 4  3 4 14  off   subtitle
# 15 2 4  2 4 15  off      title
# 16 9 4  9 4 16  off    caption

To align the title with the left edge of the plot, we can change the l value to 1.

g$layout$l[g$layout$name == "title"] <- 1

Draw the modified grid:

grid::grid.draw(g)

Result: enter image description here

Weihuang Wong
  • 12,868
  • 2
  • 27
  • 48
14

Since the release of ggplot 3.3.0 you can also use plot.title.position = "plot" to position the title and plot.caption.position = "plot subtitle at the left side of the full plot.

ggplot(data = economics, aes(x = date, y = unemploy)) +
    geom_line() +
    ggtitle("Unemployment in USA between 1967 and 2007") +
    xlab("") +
    ylab("Unemployed [thousands]") +
    theme(plot.title.position = "plot")

enter image description here

colonus
  • 189
  • 1
  • 8
8

I wrote the ggdraw() layer in cowplot specifically so that I could make annotations easily anywhere on a plot. It sets up a coordinate system that covers the entire plot area, not just the plot panel, and runs from 0 to 1 in both the x and y direction. Using this approach, it is easy to place your title wherever you want.

library(cowplot)
theme_set(theme_gray()) # revert to ggplot2 default theme

p <- ggplot(data = economics, aes(x = date, y = unemploy)) +
  geom_line() +
  ggtitle("") + # make space for title on the plot
  xlab("") +
  ylab("Unemployed [thousands]")

ggdraw(p) + draw_text("Unemployment in USA between 1967 and 2007", 
                      x = 0.01, y = 0.98, hjust = 0, vjust = 1,
                      size = 12)  # default font size is 14, 
                                  # which is too big for theme_gray()

enter image description here

Claus Wilke
  • 16,992
  • 7
  • 53
  • 104
5

Another way to do this is to utilize theme(). Use the labs function to label all your titles x = for x axis, y = for y axis, title = for plot title, fill = or colour = if you have a legend you want to put a title. Inside theme() is hjust = 0, this will left justify the plot title to the left. You can delete hjust = 0 and the plot title will be centered align.

labs(x = 'Sex', y = 'Age Mean', title = 'Suicide 2003-2013 Age Mean by Sex') +
  theme(plot.title = element_text(family = 'Helvetica', 
                              color = '#666666', 
                              face = 'bold', 
                              size = 18, 
                              hjust = 0))
redeemefy
  • 4,521
  • 6
  • 36
  • 51