在外部 LaTeX 文件中访问 YAML 参数作为宏

Accessing YAML parameters as macros within external LaTeX files

我正在寻找将变量(或 LaTeX 宏)添加到 YAML header 或之后不久的方法,以便它们可以在属于我的一部分的外部 .tex 文件中使用(模块化)报告。

我的 .rmd 文件

---
output:
  pdf_document:
    latex_engine: xelatex
    includes:
      before_body: some.tex
params:
  cat: "Felix"
  numb: 14
---

# chapter
Oh my \textbf{`r params$cat`}. 
$x = `r 2*params$numb`^2$

<!-- Trying again to get the parameter -->
\input{some.tex}

我的 some.tex 文件:

`r params$cat`

输出

Hoped-for输出

我希望能够以某种方式传递来自 YAML header(或什至在其下方)的变量以供 LaTeX 使用,以便可以在一个文件中查看和更改所有重要且定期更新的参数地方。

我相信你们可以使用 lua-过滤器一起编写代码。

首先想出你自己的包含机制(因为这需要在变量替换之前发生,所以你不能使用乳胶的\input),但是例如this filter:

function Para (elem)
  if #elem.content == 1 and elem.content[1].t == "Image" then
    local img = elem.content[1]
    if img.classes[1] == "markdown" then
      local f = io.open(img.src, 'r')
      local blocks = pandoc.read(f:read('*a')).blocks
      f:close()
      return blocks
    end
  end
end

然后用例如变量替换this filter:

local vars = {}

function get_vars (meta)
  for k, v in pairs(meta) do
    if v.t == 'MetaInlines' then
      vars["$" .. k .. "$"] = {table.unpack(v)}
    end
  end
end

function replace (el)
  if vars[el.text] then
    return pandoc.Span(vars[el.text])
  else
    return el
  end
end

return {{Meta = get_vars}, {Str = replace}}

这应该像这样工作:

---
output:
  pdf_document:
    latex_engine: xelatex
    pandoc_args:
      - '--lua-filter=include.lua'
      - '--lua-filter=substitution.lua'
name: Samuel
---

Look, I can include files:

![](include.md){.markdown}

include.md中:

Look, I can use variables: $name$

只有这个half-way。仍然没有文件 header-input...

也许这个答案会给其他人一个构建的想法..

---
output:
  pdf_document:
    latex_engine: xelatex
params:
  cat: "Felix"
  numb: 14
header-includes:
- \usepackage{fancyhdr}
- \pagestyle{fancy}
- \fancyhead[CO,CE]{`r params$cat`}
---

# CHAPTER 1
Oh my \textbf{`r params$cat`}. 
$x = `r 2*params$numb`^2$

```{r child = 'some.tex'}
```

截图pdf

您可以在 YAML header 中创建 TeX 或 LaTeX 宏,然后在您的 some.tex 文件中使用它。

例如,将其放入您的主文件中:

---
output:
  pdf_document:
    latex_engine: xelatex
      includes:
        before_body: some.tex
header-includes:
- \def\thecat{`r params$cat`}
params:
  cat: "Felix"
  numb: 14
---


# chapter
Oh my \textbf{`r params$cat`}. 
$x = `r 2*params$numb`^2$

\input{some.tex}

并将其放入 some.tex:

\thecat

一切都会按照您想要的方式显示。

如果您正在寻找可能最符合 R Markdown 工作流程的内容,您可以自定义用于构建 LaTeX 输出的模板,并将所有额外的 LaTeX 代码直接添加到此。

1.正在复制模板

首先,我们必须复制template used by R Markdown。以下代码将在您当前的工作目录中创建它:

file.copy(system.file("rmd/latex/default-1.17.0.2.tex",
          package = "rmarkdown"), "template.tex")

2。添加变量

使用我们的副本,我们可以定义我们自己的 pandoc variables,它将被插入到输出文档中。这允许我们在文档的 YAML 部分指定参数,它们将以输出格式更新。它与允许我们添加 titleauthordate 并将它们添加到输出格式中的机制完全相同。

我在 lines 253-255 文档的开头部分添加了一些代码。确切的位置并不重要,但我也倾向于将我的自定义设置放在 \begin{document} 参数之前:

\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[LO, LE]{$params.value$}
\fancyhead[RO, RE]{$yourParam$}

3。从 R Markdown 调用模板

我们可以将自定义模板引用到我们的 R Markdown 文档 as explained here。这是我的最小示例:

---
output:
  pdf_document:
    template: template.tex
params:
  value: Text
yourParam: "`r Sys.Date()`"
---

`r params$value`

这两个参数将被添加到输出中以替换 $params.value$$yourParam$,并导致以下输出:

该示例突出显示了 YAML 参数如何不必嵌套在 params 参数中,正如您在原始问题中指定的那样。如果您想构建 parameterized report

,在参数中指定它们主要有好处

Note: the approach of replacing variables using the pandoc notation $variable$ is only possible for the main template file defined under the template option. It won't work for any of the includes arguments or any other external LaTeX files. See here for more details.

让我改一下问题:目标是编写参数化报告。此报告使用 \input 嵌入 TEX 文件(例如 some.tex)。您正在寻找一种方法来访问 some.tex.

中的 YAML 参数

一种方法是根据 YAML 参数定义 LaTeX 宏,例如YAML 参数 cat: "Felix" 变为 \newcommand{\cat}{Felix}。然后可以在整个文档中使用这些 TEX 宏。 (在主文件中,r params$cat 也可以工作,但是由于 some.tex 没有被编织,这里只有 \cat 工作。)

首先,对 R 代码求值。它读取所有 YAML 参数并将相应的宏写入 myparams.tex.1 通过 header-includes 生成的文件 myparams.tex 包含在中间 TEX 文件中,该文件终于编译成PDF了。

主 RMD 文件:

---
output: pdf_document
header-includes: "\input{myparams.tex}"
params:
  cat: "Felix"
  numb: 14
---

```{r, include = FALSE}
if (file.exists("myparams.tex")) {
  file.remove("myparams.tex") # CAUTION: this will DELETE any existing file "myparams.tex"
}
for (param in names(params)) {
  cat(sprintf("\newcommand{\%s}{%s}\n", param, params[param]), file = "myparams.tex", append = TRUE)
}
```

Oh my \cat. 
$x = 2 \cdot \numb^2$

Or alternatively: Oh my `r params$cat`. 

\input{some.tex}

some.tex:

Oh my \cat. % Here, `r params$cat` won't work.

输出:

Oh my Felix. x = 2 · 14²

Or alternatively: Oh my Felix.

Oh my Felix, again.

myparams.tex的内容(动态生成):

\newcommand{\cat}{Felix}
\newcommand{\numb}{14}

1 为所有新的 LaTeX 宏使用唯一前缀可能是个好主意,以避免内置 LaTeX 命令和具有相同名称的 YAML 参数之间发生冲突。