10

The default alignment is for a ggplot title to be left-aligned to the plot.background element. Others have noted that you can use plot.title = element_text(hjust = 0.5) to center the title.

However, I want to center the title across the entire panel as oppose to just the plot. I have done this in the past by modifying the hjust to push the title so that it appears centered, but value of hjust is dependent on the length of the title which makes it really tedious to set when I'm batch-producing graphs.

Is it possible to consistently set the title elements of a ggplot to be centered across the panel.background?

library(reprex)
library(tidyverse)
data(mtcars)

mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  labs(title="This title is left-aligned to the plot")

mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  labs(title="This title is center-aligned to the plot width.")+
  theme(plot.title = element_text(hjust = 0.5))

mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  labs(title="Short title, still works")+
  theme(plot.title = element_text(hjust = 0.5))

mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  labs(title="This title is roughly center-aligned to panel")+ 
  theme(plot.title = element_text(hjust = 0.37)) # I know I can adjust this, but it would require a manual fix each time

Suggestion by @user20650

p <- mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  #labs(title="Short title, still works")+
  theme(plot.title = element_text(hjust = 0.5)) 

gridExtra::grid.arrange( top=grid::textGrob("This title is center-aligned to panel"),p  )

Created on 2018-09-24 by the reprex package (v0.2.1)

grad_student
  • 317
  • 1
  • 5
  • 13
  • 2
    one way would be to rbind a textGrob with the title to the plot. Here is a way using grid.arrange that does the work for you `gridExtra::grid.arrange( top=grid::textGrob("This title is roughly center-aligned to panel"), p )` – user20650 Sep 23 '18 at 19:10
  • @user20650, this looks good, I had looked into Grid.arrange before but not like this. Is there an argument that will allow me to get rid of the padding if I stack another textGrob for the subtitle? If i use your `gridExtra::grid.arrange(top=grid::textGrob("This title is roughly center-aligned to panel"), grid::textGrob("subtitle"), p )`, the textgrobs are definitely centered across the entire panel but there is a lot of vertical spacing. Any way to reduce this? Ideally I want to keep the title and subtitle text separate so I can style them differently. – grad_student Sep 23 '18 at 19:27
  • 2
    `grid.arrange( top=grobTree(textGrob("This title"), textGrob("\n\nThis subtitle", gp=gpar(cex=0.8))), p, padding=unit(2, "line") )` : not sure how robust it will be as title fontsize etc is increased. – user20650 Sep 23 '18 at 19:39
  • pls see https://stackoverflow.com/questions/31630020/changing-multiple-line-title-in-multiplot-ggplot2-using-grid-arrange – user20650 Sep 23 '18 at 20:17
  • 1
    @user20650, Thanks! For now, I think I'll go with your suggestion. It actually works pretty well since the title and subtitle font sizes are standardized across all the graphs so once I figured out the right number of new lines to put in the subtitle text it did not need to change. I'll update my question with your code. – grad_student Sep 24 '18 at 15:22
  • Does this answer your question? [How to center ggplot plot title](https://stackoverflow.com/questions/46287086/how-to-center-ggplot-plot-title) – Martin Modrák Feb 28 '20 at 13:50
  • Is it possible to align the title with the left side of the bars? – MartineJ Aug 30 '21 at 16:50

3 Answers3

6

There is now the option in theme to call plot.title.position to center the plot title to the entire plotting area, not just the plot panel. If you set plot.title.position = "plot" in theme(), it will center the title and subtitle to the whole plotting area, not just above the panel.

library(reprex)
library(tidyverse)
data(mtcars)

mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  labs(title="This title is center-aligned to the plot width.")+
  theme(plot.title = element_text(hjust = 0.5),
        plot.title.position = "plot")

This title is center-aligned to the plot width.

Casey
  • 93
  • 1
  • 6
3

One approach is to change the position of the title grob so that it starts from the left edge:

p <- mtcars %>% 
  rownames_to_column(var = "model") %>% 
  top_n(8,wt) %>% 
  ggplot(aes(x =model, y = wt))+
  geom_col()+
  coord_flip()+
  labs(title="This title is left-aligned to the plot") +
  theme(plot.title = element_text(hjust = 0.5))

library(gridExtra)
g <- ggplotGrob(p)
g$layout$l[g$layout$name == "title"] <- 1
grid::grid.draw(g)

enter image description here

Weihuang Wong
  • 12,868
  • 2
  • 27
  • 48
  • I like this solution because it allows me to continue to use the labs arguments, but I'm worried about saving as a png? My workflow after creating the graph is to use `ggsave` to save as a png. It seems like using `ggplotGrob` is not one of the accepted objects that ggsave accepts? – grad_student Sep 24 '18 at 15:19
  • `ggsave("test.png")` works for me, since it defaults to saving the last plot displayed. Or perhaps `ggsave("test.png", arrangeGrob(g))`, per the discussion here https://stackoverflow.com/questions/17059099/saving-grid-arrange-plot-to-file. – Weihuang Wong Sep 24 '18 at 15:58
0

Another option is to use the patchwork library and it's plot_annotation, so you'll have:

mtcars %>% 
     rownames_to_column(var = "model") %>% 
     top_n(8,wt) %>% 
     ggplot(aes(x =model, y = wt))+
     geom_col()+
     coord_flip()+
     patchwork::plot_annotation(title="This title is very long and centered on the whole plot", 
          theme = theme(plot.title = element_text(hjust = 0.5)))

enter image description here

Martin Modrák
  • 746
  • 8
  • 17