可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm looking for ways to add variables (or LaTeX macros) to the YAML header or soon after such that they can be used in external .tex
files that are a part of my (modularised) report.
My .rmd
file
---
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}
My some.tex
file:
`r params\$cat`
Output
Hoped-for output
I want to be able to somehow pass the variables from the YAML header (or even just below it) to be used by LaTeX so that all important and regularly updated parameters can be viewed and changed in one place.
回答1:
If you are looking for something which perhaps is most in keeping with the R Markdown workflow, you can customise the template which is used to build the LaTeX output and add all the extra LaTeX code directly to this.
1. Copying Template
Firstly, we must make a copy of the template used by R Markdown. The following code will create this in your current working directory:
file.copy(system.file("rmd/latex/default-1.17.0.2.tex",
package = "rmarkdown"), "template.tex")
2. Adding Variables
With our copy, we can define our own pandoc variables which will be inserted into the output document. This allows us to specify parameters in the YAML section of the document and they will be updated in the output format. It is exactly the same mechanism which allows us to add title
, author
, date
and for them to be added to the output format.
I have added some code to the front matter of the document at lines 253-255. The exact location doesn't matter, but I also tend to put my customisations before the \begin{document}
argument:
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[LO, LE]{$params.value$}
\fancyhead[RO, RE]{$yourParam$}
3. Calling Template from R Markdown
We can reference the custom template to our R Markdown document as explained here. Here is my minimal example:
---
output:
pdf_document:
template: template.tex
params:
value: Text
yourParam: "`r Sys.Date()`"
---
`r params$value`
The two parameters will be added to the output replacing the $params.value$
and $yourParam$
, and result in the output below:
The example highlights how the YAML parameters don't have to be nested within the params
argument, as specified in your original question. Having them specified within the parameters mainly has benefits if you want to build a 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.
回答2:
This comes only half-way. Still no file as header-input...
Maybe this answer will give someone else an idea to build on..
---
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'}
```
screenshot pdf
回答3:
I'm sure you can code something together using lua-filters.
First come up with your own include-mechanism (since this needs to happen before variable-substitution, so you cannot use latex's \input
), but e.g. 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
Then do the variable substitution with e.g. 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}}
This should then work like:
---
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}
And in include.md
:
Look, I can use variables: \$name\$
回答4:
You can create a TeX or LaTeX macro in the YAML header, and use that in your some.tex
file.
For example, put this in your main file:
---
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}
and put this in some.tex
:
\thecat
and things will display the way you want.
回答5:
Let me rephrase the question: The goal is to write a parametrized report. This report uses \input
to embed a TEX file (e.g. some.tex
). You are looking for a way to access the YAML parameters in some.tex
.
One way to do this is to define LaTeX macros according to the YAML parameters, e.g. the YAML parameter cat: "Felix"
becomes \newcommand{\cat}{Felix}
. These TEX macros can then be used throughout the document. (In the main file, r params$cat
would work as well, but as some.tex
is not being knitted, here only \cat
works.)
First, the R code is evaluated. It reads all YAML parameters and writes corresponding macros into myparams.tex
.1 Via header-includes
the generated file myparams.tex
is included in the intermediate TEX file, which is finally being compiled to PDF.
Main RMD file:
---
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.
Output:
Oh my Felix. x = 2 · 14²
Or alternatively: Oh my Felix.
Oh my Felix, again.
Contents of myparams.tex
(dynamically generated):
\newcommand{\cat}{Felix}
\newcommand{\numb}{14}
1 It might be a good idea to use a unique prefix for all new LaTeX macros to avoid clashes between build-in LaTeX commands and YAML parameters with the same name.