在外部 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:
{.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 部分指定参数,它们将以输出格式更新。它与允许我们添加 title
、author
、date
并将它们添加到输出格式中的机制完全相同。
我在 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 参数之间发生冲突。
我正在寻找将变量(或 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:
{.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 部分指定参数,它们将以输出格式更新。它与允许我们添加 title
、author
、date
并将它们添加到输出格式中的机制完全相同。
我在 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 thetemplate
option. It won't work for any of theincludes
arguments or any other external LaTeX files. See here for more details.
让我改一下问题:目标是编写参数化报告。此报告使用 \input
嵌入 TEX 文件(例如 some.tex
)。您正在寻找一种方法来访问 some.tex
.
一种方法是根据 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 参数之间发生冲突。