13

The "lege artis" way to center justify a plot title in ggplot - plot.title = element_text(hjust = 0.5) - centers the title over plot area excluding axis labels.

This can get ugly when the axis labels are very long, such as this plot of songs in Mary Poppins Soundtrack vs. their character length.

length of songs in Mary Poppins Soundrack

library(tidyverse)

mary_poppins <- data_frame(song = c("Overture", "Sister Suffragette", "The Life I Lead", "The Perfect Nanny", "A Spoonful of Sugar", "Pavement Artist", "Jolly Holiday", "Supercalifragilisticexpialidocious", "Stay Awake", "I Love to Laugh", "A British Bank", "Feed the Birds ", "Fidelity Fiduciary Bank", "Chim Chim Cher-ee", "Step in Time", "A Man Has Dreams", "Let's Go Fly a Kite"
))

mary_poppins <- mary_poppins %>%
  mutate(len = nchar(song))

ggplot(data = mary_poppins, aes(x = reorder(song, len), y = len)) +
  geom_col(fill = "firebrick") +
  coord_flip() +
  theme_light() +
  theme(axis.title.y = element_blank(),
        axis.text = element_text(size = rel(1.5)),
        plot.title = element_text(size = rel(2.5), face = "bold", hjust = 0.5, 
                                  margin = margin(t = 10, b = 20, unit = "pt"))) +
  ggtitle("Mary Poppins") +
  ylab("Lenght of title (characters)")

Is there a way to center the title over the total plot area, i.e . including the area taken over by axis labels?

Jindra Lacko
  • 7,814
  • 3
  • 22
  • 44

6 Answers6

7

A simple way to solve the problem is to add the following to the plot:

theme(plot.title.position = 'plot', 
      plot.title = element_text(hjust = 0.5))

The first part tells ggplot to use the entire plot as a reference for the centering, and the second part centers the title.

5

Short solution I've found:

theme(plot.title = element_text(hjust = -0.2))

hjust parameter controls distance from the left alignment to the y axis. Negative values move text to the left

3

Solution adding white space to centre title:

Add spaces after the title with:

ggtitle(paste0("Mary Poppins", paste0(rep("", 30), collapse = " ")))

For the output like this:

enter image description here

Not perfect solution, but works.

pogibas
  • 27,303
  • 19
  • 84
  • 117
3

Alternately, you can use gridExtra::grid.arrange and grid::textGrob to create the title without needing to pad it visually. This basically creates a separate plot object with your title and glues it on top, independing of the contents of your ggplot call.

First store your whole ggplot call in a variable, e.g. p1:

grid.arrange(textGrob("Mary Poppins", 
               gp = gpar(fontsize = 2.5*11, fontface = "bold")), 
             p1, 
             heights = c(0.1, 1))

You have to translate your theme() settings to gpar(). The base size of theme_light is 11, which is where the 2.5*11 comes from (and the 2.5 from your rel(2.5)).

enter image description here

The advantage here is that you know your title will be truly centered, not just close enough by eye.

Brian
  • 7,900
  • 1
  • 27
  • 41
2

As I replied in an essentially duplicate question, you can use the patchwork library and it's plot_annotation, so you'll have:

library(tidyverse)

mary_poppins <- data_frame(song = c("Overture", "Sister Suffragette", "The Life I Lead", "The Perfect Nanny", "A Spoonful of Sugar", "Pavement Artist", "Jolly Holiday", "Supercalifragilisticexpialidocious", "Stay Awake", "I Love to Laugh", "A British Bank", "Feed the Birds ", "Fidelity Fiduciary Bank", "Chim Chim Cher-ee", "Step in Time", "A Man Has Dreams", "Let's Go Fly a Kite"
))
mary_poppins <- mary_poppins %>%
  mutate(len = nchar(song))

ggplot(data = mary_poppins, aes(x = reorder(song, len), y = len)) +
  geom_col(fill = "firebrick") +
  coord_flip() +
  theme_light() +
  theme(axis.title.y = element_blank(),
        axis.text = element_text(size = rel(1.5))) +
  patchwork::plot_annotation("Mary Poppins", 
        theme = theme(plot.title = element_text(size = rel(2.5), face = "bold", hjust = 0.5, 
                                  margin = margin(t = 10, b = 20, unit = "pt")))) +
  ylab("Lenght of title (characters)")

Since plot_annotation is designed for multipanel plots, it will not inherit the theme of the plot you are constructing, so you need to give it separately. It will however honor any global theme.

The resulting plot is (hopefully) what you need.

plot with centered title

Martin Modrák
  • 746
  • 8
  • 17
1

If you're in a hurry, adding spaces after title in ggtitle will also work...

ggtitle("Mary Poppins                                 ") +

Output: Center Mary Poppins Title

Dan Tarr
  • 209
  • 3
  • 8