原文链接 🔗 5 Pull it Together
写论文时需要引用各种书籍和文章,一般情况下它们包括在 R 创建的表格和图片中。我们要做的是快速将包括这些图表内容的 Markdown 文件转换为格式正确的学术论文,而不损失任何必不可少的学术结构(在输出端)和 Markdown 的便利性和可转换性(在输入端)。我们希望从同一个来源便捷地获得美观的输出,例如 HTML、PDF 和 DOCX 格式,同时在成本最小化转换步骤之外(理想情况下),对输出后的结果不再进行其他处理,以上这些是我们能够做到的。
示例文档流程如上图所示,看起来有点混乱,但我保证实际操作不像上面那么复杂,一股脑把它说清楚可能听起来有点疯狂。但是,实际上只有两个主要步骤。首先,knitr
将 .Rmd
文件转换为 .md
文件,其次,John MacFarlane 出色的 Pandoc 将 .md
文件转换为 HTML、knitr
和 pandoc
不需要进行自定义设置,保持默认设置就可以。我希望你做的只是使用这些工具的相关选项和设置,以及一些模板和文档示例,它们展示了如何在实际操作中生成漂亮的输出结果。
我在 Emacs 中写所有的东西,在 前面 我们已经谈到了 Emacs,但用不用它取决于你,使用你喜欢的任何文本编辑器都可以,只是你觉得顺手。自定义的 .tex
文件,但现在它们只是在后台工作。Pandoc 使用这些
如果你把这些文件安装在 ~/.pandoc/
目录下,这是 Pandoc 的配置文件存放目录。此外,我还建立了一个示例 md-starter
项目和一个 rmd-starter
项目,这两个是用 Markdown(只有一个 .md
文件,没有 R)写的论文的项目文件夹骨架,以及用 .rmd
文件写论文的一个开篇。总的来说,这些模板包括基本的启动文件和 Makefile
—— 用来生成 .html
、.tex
、.pdf
和 .docx
文件。
---
title: "A Pandoc Markdown Article Starter"
author:
- name: Kieran Healy
affiliation: Duke University
email: [email protected]
- name: Joe Bloggs
affiliation: University of North Carolina, Chapel Hill
email: [email protected]
date: January 2014
abstract: "Lorem ipsum dolor sit amet."
---
# Introduction
Lorem ipsum dolor sit amet, consectetur adipisicing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua [@fourcade13classsituat]. Notice that citation.
# Theory
Lorem ipsum dolor sit amet, consectetur adipisicing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua [@fourcade13classsituat].
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
让我们从一个简单的没有 R 代码的 Markdown 文件开始,因此就没有上图中 kniter 及其左边的部分。上方代码块展示了 article-markdown.md
这个实例文件的开头部分,上半部分是 Pandoc 可以读取的文档元数据,pandoc-templates 仓库 中的 HTML 和
学术工作中,参考文献的有效管理尤为重要。pandoc-citeproc
是 Pandoc 中处理参考文献的扩展,它可以和 pandoc
一起安装。参考文献可以多种格式存储(例如 BibTeX、EndNote),在 .md
文档中,参考文献的引入是通过引用键实现的,例如 [@healy14datavisualsociol]
。当 pandoc
转换文档时,引用键被替换为参考文献,像(Healy & Moody,2014)这样,完整的参考文献条目会列在文后的参考文献中,更多关于引用的细节,可以阅读 Pandoc 说明文档。此外,Pandoc 还可以处理文本标签和交叉引用,叫做 pandoc-crossref
的一个扩展实现了 @label
处理图片、表格、公式、定理、代码等的功能。
Pandoc 管理引用的方式不止一种,但在这里我们只使用最独立的方法。简单的文档可以用单个 .md
文件书写,包括数据分析的文档用 .Rmd
文件写,然后将 .Rmd
编译为 .md
文件,再转换成 PDF 或 HTML。这里给出一个最简单的例子, 文件 mypaper.md
可以通过打开终端窗口并输入下面的命令将其转换为 mypaper.pdf
。
pandoc mypaper.md -o mypaper.pdf
# 用 make
实现自动化
因为我们可能会经常运行上面这些的命令,所以自动执行命令会更方便,并添加一些额外的附加功能来适应我们在文件中增减的内容,例如作者信息和其他元数据,以及处理参考文献和交叉引用的功能。这些都是由 pandoc
在命令行中通过各种操作完成的,并使用一些扩展来确保参考文献和交叉引用准确无虞。为了避免反复输入很长的命令,我们最好通过自动化来实现这一过程。当我们的最终输出文件在正确生成之前可能有许多先决条件时,这种自动化特别有用,并且我们希望电脑能更智能一点,知道什么需要重新处理,在什么条件下处理。这样的话,如果一张图片没有发生改变,我们将不会重新运行(可能很耗时的)R 脚本来再次创建它,除非我们必须这样做。
我们使用一个叫做 make
的工具来实现这个自动化流程。在我们的项目文件夹中,有一个纯文本文件 Makefile
,其中包含一些规则,用于管理如何生成可能具有许多先决条件的目标文件。在这里,PDF 或 HTML 是目标文件,各种图片和数据表格是先决条件,如果生成图片和表格的代码发生更改,最终文档也将更改。make
从目标文档开始,沿着先决条件链向后工作,根据需要重新编译或重新创建它们。
make
是一个非常强大的工具!想要快速入门 make
,可以看看 Karl Broman 的 minimal make(顺便提一下,Karl Broman 有 很多教程和指南,可以为这里提到的许多工具提供准确而简洁的参考,例如 进行可复现的研究、Git 和 GitHub 指南、knitr 的简短介绍。)
按照 Karl Broman 的例子,假设你有一篇用 Markdown 写的论文 paper.md
,它包含了一张由 R 脚本 fig1.r
生成的图片 fig1.pdf
,当然可以有一个 .Rmd
产生输出的完整文件,但有些情况下这并不是最适合的。你的目标是得到 PDF 格式的论文,当 paper.md
中的文本发生变化时,paper.pdf
必须重新创建,同样,当我们更改 R 脚本 fig1.r
,那么 fig1.pdf
也需要更新,因此 paper.pdf
还是需要重新创建,但是使用 make
我们可以简化处理这个过程。
下面是一个基本的 Makefile
示例:
## Read as "mypaper.pdf depends on mypaper.md and fig1.pdf"
mypaper.pdf: mypaper.md fig1.pdf
pandoc mypaper.md -o mypaper.pdf
## Read as "fig1.pdf depends on fig1.r"
fig1.pdf: fig1.r
R CMD BATCH fig1.r
2
3
4
5
6
7
Makefiles
有个最大的问题,就是不知道为什么它使用 tab 键而不是空格来缩进与规则相关的命令。如果你使用空格,make
将无法正常工作。回到上述的 Makefile
示例,在命令行键入 make
,它将会检查目标文件(makefile.pdf
)及其所有依赖文件的状态。如果目标文件不存在,make
将根据指定规则创建,如果目标文件存在,make
将检查自上次创建以来其先决条件是否发生了更改。如果是,它将重新创建该文件,先决条件链向后传递,因此如果更改 fig1.r
,在运行创建 mypaper.pdf
的规则中的命令之前,make
将注意到更改并重新运行来创建 fig1.pdf
。当然,你可以选择只调用来自 makefile
的单个规则,例如,在命令行中输入 make fig1.pdf
而不是 make
,这将只评估 fig1.pdf
的规则以及和它相关的先决条件。
对于上面这样一个简单的例子,make
主要是提供一个小小的便利,省去了一遍又一遍地输入一系列命令来创建论文的麻烦。但是,一旦你拥有包含许多文档和依赖项的项目,它就变得非常有用,例如,由不同章节组成的论文,每个章节都包含图片和表格,而这些图片和表格依赖于各种 R 脚本来进行设置和清理数据,这种情况下,make
就成为一种非常强大且有用的方法,可以确保最终的输出结果一定是最新的。
为了处理更复杂的项目和各种先决条件,make
可以使用许多变量来保存你键入 figure-x.pdf
目录中每个项的名称。
示例 md-starter
项目 中的 Makefile
可以按照指令将工作目录中任何的标记文件转换为 .html
、.tex
或 .docx
文件。例如,在命令行输入 make html
会把目录中所有的 .md
文件转换为 .html
文件,输出的 PDF(由命令 make pdf
实现)看起来就像 这篇文章。
Makefile
的不同部分定义了一些变量,用于指定不同文件类型之间的关系。实质上,根据规则,目录中的所有 PDF 文件都依赖于对 .md
具有相同名称的文件的更改,HTML 文件是如此,pandoc
命令出现,将 Markdown 文件输出最终的结果。Makefile
文件如下方代码块所示,它使用一些变量作为简写,以及像 $@
和 $<
这样的特殊变量,分别表示「当前目标的名称」和「当前先决条件的名称」。
## What extension (e.g. md, markdown, mdown) is being used
## for markdown files MEXT = md
## Expands to a list of all markdown files in the working directory
SRC = $(wildcard *.$(MEXT))
## Location of Pandoc support files.
PREFIX = /Users/kjhealy/.pandoc
## Location of your working bibliography file
BIB = /Users/kjhealy/Documents/bibs/socbib-pandoc.bib
## CSL stylesheet (located in the csl folder of the PREFIX directory).
CSL = apsa
## x.pdf depends on x.md, x.html depends on x.md, etc
PDFS=$(SRC:.md=.pdf)
HTML=$(SRC:.md=.html)
TEX=$(SRC:.md=.tex)
DOCX=$(SRC:.md=.docx)
## Rules -- make all, make pdf, make html. The `clean` rule is below.
all: $(PDFS) $(HTML) $(TEX) $(DOCX)
pdf: clean $(PDFS)
html: clean $(HTML)
tex: clean $(TEX)
docx: clean $(DOCX)
## The commands associated with each rule. The first one is run with
## make html.
%.html: %.md
pandoc -r markdown+simple_tables+table_captions+yaml_metadata_block \
-w html -S --template=$(PREFIX)/templates/html.template \
--css=$(PREFIX)/marked/kultiad-serif.css --filter pandoc-crossref \
--filter pandoc-citeproc --csl=$(PREFIX)/csl/$(CSL).csl \
--bibliography=$(BIB) -o $@ $<
## Same goes for the other file types.
## Watch out for the TAB before 'pandoc'
%.tex: %.md
pandoc -r markdown+simple_tables+table_captions+yaml_metadata_block \
--listings -w latex -s -S --latex-engine=pdflatex \
--template=$(PREFIX)/templates/latex.template \
--filter pandoc-crossref --filter pandoc-citeproc \
--csl=$(PREFIX)/csl/ajps.csl --filter pandoc-citeproc-preamble \
--bibliography=$(BIB) -o $@ $<
%.pdf: %.md
pandoc -r markdown+simple_tables+table_captions+yaml_metadata_block \
--listings -s -S --latex-engine=pdflatex \
--template=$(PREFIX)/templates/latex.template \
--filter pandoc-crossref --filter pandoc-citeproc \
--csl=$(PREFIX)/csl/$(CSL).csl --filter pandoc-citeproc-preamble \
--bibliography=$(BIB) -o $@ $<
%.docx: %.md
pandoc -r markdown+simple_tables+table_captions+yaml_metadata_block \
-s -S --filter pandoc-crossref --csl=$(PREFIX)/csl/$(CSL).csl \
--bibliography=$(BIB) -o $@ $<
clean:
rm -f *.html *.pdf *.tex *.aux *.log *.docx
.PHONY: clean
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
需要注意的是,pandoc
命令是单行文本解释,而不是由 return
键分隔的几行。但是可以使用 \
符号告诉 make
继续到下一行而不中断。使用上述 Makefile
文件,键入 make pdf
将运行 Pandoc 命令,将文件目录中所有 .md
文件一次性全部转换为一个 PDF 文件,并使用 APSR 参考文献样式、我的 socbib-pandoc.bib
的 .bib
文件。
但是,不要盲目使用 Makefile
,最好花点时间了解它的 make
工作原理以及它是如何帮助你的,make
官方手册 是非常清楚详细的。make
保守的先决条件链可能使编写复杂项目规则变得棘手,在编写或检查 Makefile
及其特定规则时,使用该 --dry-run
命令很有用 ,例如 make --dry-run
,会输出 make
的命令列表,但不会执行。你可以在至少包含一个 .md
文件的目录下,尝试使用上述 Makefile
命令,例如,输入 make pdf --dry-run
、make docx --dry-run
或 make clean --dry-run
,看看会输出什么。
许多项目所需的特定步骤可能非常简单,并且不需要使用任何变量或其他不必要的东西。如果你发现自己反复运行相同的命令来生成文档(例如清理数据,初步运行代码,生成数据,输出最终文档),那么 make
可以做很多事情来自动化这一过程。有关 Makefiles
完成数据分析相关的更多示例,可以参考 Lincoln Mullen 对他使用 make
来完成工作的 论述。
我的示例仓库 包含 一个.Rmd
示例文件,文件中的代码块提供了如何在文档中生成表格和图片的示例,特别是有一些可以传递给 knitr 的很有用的选项,可以参考 knitr 项目页面,有大量的文档和更多的示例。
要从 article-knitr.Rmd
文件输出结果,你当然可以在工作目录中启动 R,加载 knitr
处理该文件,这将生成 article-knitr.md
文件,以及保存在 figures/
文件夹中的一些图片(以及文件夹 cache/
中的一些工作文件)。我们在 .Rmd
文件中进行设置,这样 knitr
就可以输出由 R 生成的图片的 PNG 和 PDF 版本,这为便捷地转换为 HTML 和 article-knitr.md
文件生成 .tex
,就可以像以前一样在命令行输入 make
命令来生成 .html
、.tex
和 .pdf
文件。但是,make
也可以自动完成第一步,rmd-starter
项目中有一个示例 Makefile
,开头是 .Rmd
文件,结果将从那里输出。
可以这样操作:打开终端窗口,输入
xcode-select --install
。也可以使用 Homebrew 包管理器 来安装pandoc
和很多其他工具。 ↩︎