Многострочный заголовок ggplot с различным размером шрифта, лицом и т. Д.

Я исследовал SO и другие сайты, но не могу найти решение моей проблемы с моим ggtitle(), Я знаю, что есть другие примеры, но я не смог применить их непосредственно к моей проблеме успешно.

То, что я пытаюсь сделать, это создать многострочный заголовок, в котором первая строка выделена жирным шрифтом, размер = 10, а затем под этой первой строкой находится вторая (и, возможно, третья), более описательная строка (и), не выделенная жирным шрифтом, размер =8. Кикер в том, что я пытаюсь выровнять это по оси Y. Это левое обоснование делает этот вопрос уникальным, поскольку в предыдущих ответах, в том числе связанных с модератором, используется atop() который не допускает выравнивания по левому краю или не включает его в связанный ответ.

Вот как выглядит мой сюжет:

введите описание изображения здесь

title <- paste("An analysis of the mtcars dataset  ")
subheader <- paste("How does mpg change by   \n number of cyl?")

ggplot(mtcars, aes(mpg,cyl))+ 
  geom_smooth(aes(fill="Mean",level=0.095)) +
  ggtitle(paste0(title,"\n",subheader)) +
  scale_fill_grey(name='95% Confidence\n Interval',start=.65,end=.65) +
  theme(plot.title = element_text(size = rel(2.0),hjust=-.1,face="bold"))

Я пытался использовать bquote(), mtext(), atop() и даже шероховатый paste() с дополнительными пробелами для заголовка.... но я не смог найти решение.

Пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы или вам нужны разъяснения. Я ценю любую помощь!

3 ответа

Решение

Вот способ использовать пользовательские аннотации. Обоснование простое, но вы должны определить координаты для размещения текста вручную. Возможно, вы могли бы создать некоторую логику для автоматизации этого шага, если вы собираетесь делать это много.

library(grid) 

title <- paste("An analysis of the mtcars dataset  ")
subheader <- paste("How does mpg change by\nnumber of cyl?")

p1 = ggplot(mtcars, aes(mpg,cyl))+ 
  geom_smooth(aes(fill="Mean",level=0.095)) +
  scale_fill_grey(name='95% Confidence\n Interval',start=.65,end=.65) 

p1 = p1 + 
  annotation_custom(grob=textGrob(title, just="left", 
                                  gp=gpar(fontsize=10, fontface="bold")),
                    xmin=9.8, xmax=9.8, ymin=11.7) +
  annotation_custom(grob=textGrob(subheader, just="left", 
                                  gp=gpar(fontsize=8, lineheight=1)),
                    xmin=9.8, xmax=9.8, ymin=10.4) +
  theme(plot.margin=unit(c(4,rep(0.5,3)), "lines"))

# Turn off clipping
p1 <- ggplot_gtable(ggplot_build(p1))
p1$layout$clip[p1$layout$name == "panel"] <- "off"
grid.draw(p1) 

Вот три подхода, использующих tableGrob для разделения текста на несколько строк:

введите описание изображения здесь

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()))

Вы можете использовать этот подход, но оправдание невероятно привередливо. Так как atop был разработан для форматирования уравнений, он автоматически центрируется, поэтому вам нужно взломать его, вставив пробелы перед более длинным заголовком и поиграв с hjust, Похоже, что при таком подходе также существует верхний предел размера заголовка; должно быть место для пространства, чтобы отойти влево.

Что мне удалось:

library(ggplot2)
title <- paste("           An analysis of the mtcars dataset")
subheader <- paste("How does mpg change by number of cyl?")

ggplot(mtcars, aes(mpg,cyl)) + 
  geom_smooth(aes(fill="Mean",level=0.095)) +
  ggtitle(bquote(atop(bold(.(title)), atop(.(subheader), ""))))  +
  scale_fill_grey(name='95% Confidence\n Interval',start=.65,end=.65) +
  theme(plot.title = element_text(size = rel(1.3),hjust=-.6,face="bold"))

сюжет с заголовком и подзаголовком влево выровнен

Чтобы пойти дальше, вам, вероятно, придется взломатьgrid,

Другие вопросы по тегам