Here are three approaches using tableGrob to split a text into multiple lines,
title <- paste("An analysis of the mtcars dataset ")
subheader <- paste("How does mpg change by \nnumber of cyl?")
library(gridExtra)
library(grid)
table_label <- function(label, params=list()) {
params1 <- modifyList(list(hjust=0, x=0, fontsize=12, fontface=2), params)
params2 <- modifyList(list(hjust=0, x=0, fontsize=8, fontface=1), params)
mytheme <- ttheme_minimal(core = list(fg_params = params2),
colhead = list(fg_params = params1))
disect <- strsplit(label, "\\n")[[1]]
m <- as.matrix(disect[-1])
g <- tableGrob(m, cols=disect[1], theme=mytheme)
g$widths <- unit(1,"npc")
g
}
p <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_line()
## add a title, note: centering is defined wrt the whole plot
grid.arrange(p, top=table_label(paste0(title,"\n",subheader),
params=list(x=0.1)))
## to align precisely with the panel, use gtable instead
library(gtable)
titleify <- function(p, label, ...){
g <- ggplotGrob(p)
title <- table_label(label, ...)
g <- gtable_add_grob(g, title, t=1, l=4)
g$heights <- grid:::unit.list(g$heights)
g$heights[1] <-list(sum(title$heights))
grid.newpage()
grid.draw(g)
}
titleify(p, paste0(title,"\n",subheader))
## we can also hack ggplot2 to define a custom element for the title
## though be warned the hardware supporting your computer may be damaged by head banging
element_custom <- function() {
structure(list(), class = c("element_custom", "element_text"))
}
element_grob.element_custom <- function(element, label="", ...) {
table_label(label)
}
# default method is unreliable
heightDetails.gtable <- function(x) sum(x$heights)
ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
geom_line() +
ggtitle(paste0(title,"\n",subheader))+
(theme_grey() %+replace% theme(plot.title = element_custom()))