ggplot2:创建主题标题,带有Cowplot的字幕

时间:2018-06-21 16:45:19

标签: r ggplot2 cowplot

我有一个数据框列表,可用来制作ggplot的列表,然后用cowplot组合成一个绘图网格。然后,我需要附加一个共享的标题,字幕和标题。我想这样做的方式是,这些标签将具有与由labs而非cowplot::draw_label创建的主题元素相同的主题元素(大小,字体等)。

在我的实际情况下,我有几个choropleth,每个choropleth都有自己的单位和比例,这就是为什么我不能只是刻面,而是需要彼此独立地构建图。

这是数据的简化版本,以及我已加载的软件包:

library(tidyverse)
library(cowplot)

dfs <- list(
  adults_no_diploma = structure(list(
    tract = c("09003405100", "09003405200", "09003405300", "09003405401", "09003405402", "09003405500", "09003405600", "09003405700", "09003405800", "09003405900"), 
    value = c(0.08, 0.108, 0.095, 0.099, 0.105, 0.103, 0.161, 0.279, 0.056, 0.055)), 
    row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame")), 
  severe_cost_burden = structure(list(
    tract = c("09003405100", "09003405200", "09003405300", "09003405401", "09003405402", "09003405500", "09003405600", "09003405700", "09003405800", "09003405900"), 
    value = c(0.128, 0.147, 0.165, 0.1, 0.151, 0.11, 0.179, 0.184, 0.14, 0.038)), 
    row.names = c(NA, -10L), class = c("tbl_df", "tbl", "data.frame"))
)

我正在使用自定义主题(同样是简化版本):

theme_georgia <- function(...) {
  theme_gray(base_family = "Georgia", ...) + 
    theme(plot.title = element_text(face = "bold"))
}

plots <- dfs %>%
  imap(~{
    ggplot(.x, aes(x = value)) + 
      geom_density() + 
      ggtitle(.y) +
      theme_georgia()
    })

gridded <- plot_grid(plotlist = plots, nrow = 1)

cowplot annotations vignette之后,我可以用ggdraw() + draw_label("Socio-economic measures")做一个标题,并手动设置字体大小之类的东西,但是我希望以某种方式将标签定义为标题;也就是说,主题将plot.title中的所有内容都应用到该主题,创建字幕和标题也是如此。

我当前的解决方法是使用ggplot为标题和副标题创建一个空白的labs,对标题进行相同的操作,并使用cowplot::plot_grid垂直堆叠它们。

title_gg <- ggplot() + 
  labs(title = "Socio-economic measures", subtitle = "By census tract, 2016") + 
  theme_georgia()
plot_grid(title_gg, gridded, ncol = 1, rel_heights = c(0.15, 1))

解决方法尚可,但是我喜欢draw_label带来的整洁和统一。相反,我可以一个个地添加这些主题元素来模仿标题:

title_theme <- ggdraw() +
  draw_label("Socio-economic measures", 
             fontfamily = theme_georgia()$text$family, 
             fontface = theme_georgia()$plot.title$face, x = 0.05, hjust = 0)
plot_grid(title_theme, gridded, ncol = 1, rel_heights = c(0.2, 1))

我的问题是,是否有任何方法可以将这些方法结合起来以提取所有相关的主题元素,并将其快速提供给draw_label,还是以某种方式告诉draw_label,这件事是标题,应该得到标题主题元素,另一件事是字幕,依此类推。我想象这样的魔术:

ggdraw() + 
  draw_label("Socio-economic measures", theme_georgia()$plot.title_elements)

或:

ggdraw() + 
  draw_label("Socio-economic measures", type = "title") + theme_georgia()

2 个答案:

答案 0 :(得分:2)

是这样吗?

library(ggplot2)
library(cowplot)

theme_georgia <- function(...) {
  theme_gray(base_family = "Georgia", ...) + 
    theme(plot.title = element_text(face = "bold"))
}


title_theme <- calc_element("plot.title", theme_georgia())

ggdraw() + 
  draw_label(
    "Socio-economic measures",
    fontfamily = title_theme$family,
    fontface = title_theme$face,
    size = title_theme$size
  )

reprex package(v0.2.0)于2018-06-21创建。

答案 1 :(得分:1)

@Claus Wilke的解决方案已完成工作,但是我受到启发,在draw_label周围编写了包装函数,以获取模仿主题元素所需的样式。我会在这里发布,以防其他人使用,尽管这可能是一个奇怪的用例。

此函数采用主题功能,或者,如果省略theme,则从theme_get获取当前主题。它还使用主题元素的名称,例如"plot.title",并从中使用calc_element进行样式设置。所有必需的参数以及cowplot::draw_label中的任何其他内容(例如...x)都传递给hjust

library(tidyverse)
library(cowplot)

draw_label_theme <- function(label, theme = NULL, element = "text", ...) {
  if (is.null(theme)) {
    theme <- ggplot2::theme_get()
  }
  if (!element %in% names(theme)) {
    stop("Element must be a valid ggplot theme element name")
  }

  elements <- ggplot2::calc_element(element, theme)

  cowplot::draw_label(label, 
                      fontfamily = elements$family,
                      fontface = elements$face,
                      colour = elements$color,
                      size = elements$size,
                      ...
  )
}

title <- ggdraw() +
  draw_label_theme("Socio-economic measures", 
                   theme = theme_georgia(), element = "plot.title",
                   x = 0.05, hjust = 0, vjust = 1)
subtitle <- ggdraw() +
  draw_label_theme("By census tract, 2016",
                   theme = theme_georgia(), element = "plot.subtitle",
                   x = 0.05, hjust = 0, vjust = 1)

现在唯一困难的部分是在rel_heights中整齐地整理内容,在这里我可以介绍更多内容。可能有一些定位信息可以拉出主题并用于设置高度。

plot_grid(title, subtitle, gridded, ncol = 1, rel_heights = c(0.1, 0.1, 1))