将 ggplot2 字体与 Rmd/Qmd html 主题匹配

teu*_*and 5 r ggplot2 knitr r-markdown quarto

我正在寻找一种通用方法来自动将 ggplot 的字体与 html 主题使用的字体进行匹配。在下面的代码中,我想检测“yeti”主题使用“Open Sans”字体作为正文。同样,如果主题是“united”,则应该检测到字体是“Ubuntu”。

---
title: "Untitled"
output: 
  html_document:
    theme: yeti
date: "2022-09-14"
---


```{r setup, include=FALSE}
knitr::opts_chunk$set(dev = "ragg_png") # so that fonts render effortlessly
```


```{r plot}
library(ggplot2)

font <- magic_function_to_retrieve_current_font()

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  theme_gray(base_family = font)
```
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我想知道一个函数,这里称为magic_function_to_retrieve_current_font(),它执行以下操作:

  1. 它检测到该文档正在与“yeti”主题结合。
  2. 它找到主题的样式表
  3. 它在样式表中查找正文文本的 CSS 代码
  4. 从正文文本属性中,它提取“font-family”属性(并返回第一个条目)

现在(3)和(4)我可能自己弄清楚了,但我在步骤(1)和(2)上遇到了困难。是否有一些神奇的 knitr/rmarkdown/quarto 函数可以用来在编织文档时访问 YAML/主题样式表?

teu*_*and 2

所以@stefan 的评论对我帮助很大,它确定了缺失的部分。我当前的解决方案如下:

---
title: "Untitled"
output: 
  html_document:
    theme: yeti
date: "2022-09-14"
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(dev = "ragg_png")
```

```{r}
get_current_theme <- function() {
  if (interactive()) {
    yaml_meta <- rmarkdown::yaml_front_matter(
      rstudioapi::getSourceEditorContext()$path
    )
  } else {
    yaml_meta <- rmarkdown::metadata
  }
  yaml_meta$output$html_document$theme
}

get_font <- function(theme = get_current_theme()) {
  # Lookup font from theme
  fnt <- bslib::bs_get_variables(
    bslib::bs_theme(bootswatch = theme),
    "font-family-sans-serif"
  )
  # Parse variables to family names
  fnt <- strsplit(fnt, split = ", ")[[1]]
  fnt <- gsub('\"', "", fnt, fixed = TRUE)
  
  # Verify font is available
  fnt_sys <- systemfonts::system_fonts()
  idx <- match(fnt, fnt_sys$family)
  ans <- fnt[!is.na(idx)][[1]]
  
  if (length(ans) == 0) {
    ans <- "" # default font family
  }
  ans
}
```

```{r plot}
library(ggplot2)

ggplot(mpg, aes(displ, hwy)) +
  geom_point() +
  theme_gray(base_family = get_font())
```

Some regular body text to compare
Run Code Online (Sandbox Code Playgroud)

  • 很高兴看到成熟的答案和工作解决方案。很高兴为此做出贡献。不急于点。根据你的工作已经赚够了。(; (3认同)