简体   繁体   English

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

[英]ggplot2: Creating themed title, subtitle with cowplot

I have a list of data frames that I use to make a list of ggplot s, and then assemble into a grid of plots with cowplot . 我有一个数据框列表,用于创建ggplot列表,然后使用cowplot组合成一个网格图。 I need to then attach a shared title, subtitle, and caption. 然后,我需要附加一个共享的标题,字幕和标题。 I want to do this in a way that these labels will have the same theme elements (size, fontface, etc) as if they were created by labs instead of cowplot::draw_label . 我想通过某种方式使这些标签具有与由labs而不是cowplot::draw_label创建的相同的主题元素(大小,字体等)。

In my real situation, I have several choropleths that each have their own units and scales, which is why I can't just facet, but instead need to build the plots independent of one another. 在我的实际情况下,我有几个choropleth,每个choropleth都有自己的单位和比例,这就是为什么我不能只是一个方面,而是需要彼此独立地构建图。

Here's a simplified version of the data, and the packages I have loaded: 这是数据的简化版本,以及我已加载的软件包:

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

I'm working with a custom theme (again, a simplified version): 我正在使用自定义主题(再次是简化版本):

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)

Following the cowplot annotations vignette , I can make a title with ggdraw() + draw_label("Socio-economic measures") and manually set things like font size, but what I'd prefer is to somehow define that label as a title; 按照cowplot注释小插图 ,我可以使用ggdraw() + draw_label("Socio-economic measures")来创建标题,并手动设置字体大小之类的东西,但是我更希望以某种方式将该标签定义标题; that is, the theme would apply everything in plot.title to it, and the same for creating a subtitle and caption. 也就是说,主题将对plot.title所有内容plot.title到该主题,并且创建字幕和标题也是如此。

My current workaround is to make an empty ggplot with labs for the title and subtitle, do the same for a caption, and stack them vertically with cowplot::plot_grid . 我当前的解决方法是使用标题和字幕的labs制作一个空的ggplot ,对标题进行相同的操作,然后使用cowplot::plot_grid它们垂直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))

The workaround is okay, but I like the neatness and alignment you get with draw_label . 解决方法是可以的,但是我喜欢draw_label的整洁和对齐。 I could instead add in these theme elements one by one to mimic a title: 相反,我可以一个个地添加这些主题元素来模仿标题:

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

My question is whether there's any way I might combine these approaches to pull all the relevant theme elements and feed them to draw_label quickly, or somehow tell draw_label that this thing is a title and should get title theme elements, and this other thing is a subtitle, and so on. 我的问题是,是否有任何方法可以组合这些方法来提取所有相关的主题元素并将它们快速输入到draw_label ,或者以某种方式告诉draw_label这件事是标题,应该获得标题主题元素,而另一件事是副标题, 等等。 I imagine some sort of magic like this: 我想象这样的魔术:

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

or: 要么:

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

Like so? 这样吗

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
  )

Created on 2018-06-21 by the reprex package (v0.2.0). reprex软件包 (v0.2.0)于2018-06-21创建。

@Claus Wilke's solution got the job done, but I was inspired to write a wrapper function around draw_label to get the styling necessary to mimic a theme element. @Claus Wilke的解决方案已经完成了工作,但是我受到启发,在draw_label周围编写了包装函数,以获取模仿主题元素所需的样式。 I'm posting here in case it's of use to anybody else, though this might be a weird use case. 我将其发布在这里,以防其他人使用,尽管这可能是一个奇怪的用例。

This function takes a theme function or, if theme is omitted, gets the current theme from theme_get . 这个函数有一个主题功能,或者,如果theme被省略,从获取当前主题theme_get It also takes the name of a theme element, such as "plot.title" , from which it gets the styling with calc_element . 它还使用主题元素的名称,例如"plot.title" ,从中使用calc_element获得样式。 All the requisite arguments are passed to cowplot::draw_label , along with anything else in ... such as x or hjust . 所有必需的参数以及...其他任何参数(例如xhjust都传递到cowplot::draw_label 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)

Now the only hard part is lining things up neatly in the rel_heights , which I could mess around with more here. 现在,唯一困难的部分是将内容整齐地排列在rel_heights ,我可以在这里添加更多内容。 There might be positioning information to pull out of the theme and use to set the heights. 可能有一些定位信息可以拉出主题并用于设置高度。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM