作为简单、易懂的纯文本语言,Markdown 已经成为很多人日常的主要写作工具。但如论文一样的复杂文本,也可以用Markdown 完成吗?答案或许是可以。在以前的这篇能跑代码的 Markdown 编辑器——Rmarkdown 中,我已经介绍过如何使用Rmarkdown,最大程度地使用Markdown 语言完成复杂内容的写作。如果你对Rmarkdown 还不是很了解,强烈建议先阅读一下这篇文章。但学术论文写作还有两个绕不过去的坎儿,即是今天要介绍的参考文献与交叉引用。作为专为学术写作开发的Rmarkdown,完成这些任务自然也不在话下。

环境准备

为了使用方便,与上一篇文章类似,我们需要安装有以下几样东西:

  • R 语言环境,并安装rmarkdown
  • RStudio
  • Pandoc
  • LaTeX 环境(如果需要输出PDF 的话)

安装方法与配置和前一篇文章相同,这里不再赘述,但需要做两点说明。首先,RStudio 自带了一个Pandoc,如果你想直接使用无需再进行安装。如果你是独立安装的Pandoc,那么为了完成参考文献引用,还需要再安装一个pandoc-citeproc(RSdutio 自带的Pandoc 不需要)。可以在终端中执行如下代码完成安装:

brew install pandoc-citeproc

另外,Rmarkdown 的开发者为了解决LaTeX 过于臃肿的问题,开发了更为精简的TinyTex 项目。它去掉了一些不常用的LaTeX 包和文档,又支持在缺少一些包的时候自动下载,节省体积的同时省去了很多新手配置LaTeX 的麻烦。Rmarkdown 包从1.9 版本开始已经自带了TinyTex,所以如果只在Rmarkdown 中使用Tex的话,也不需要独立安装。如果想的话,可以在R 环境中运行如下命令安装即可:

install.packages("tinytex")

环境准备完毕,就可以开始正题了。下面的例子都以输出PDF 文档为例,但输出HTML 或Word 文档也同理。

设置参考文献

使用自动化方式完成参考文献引用的便利之处在于,它可以自动完成格式调整、按文中提到的顺序排列参考文献列表、无需手动比对上文提到的文章是否加入了参考文献列表中等等……一言以蔽之,你只需要在文中输入一个标签,就解决了文章内和参考文献列表里两部分的插入和排版问题,一举多得。

参考文献内容——.bib 文件

Rmarkdown 可以使用多种格式的参考文献库文件,比较常用的像.bib.bibtex 文件。简单地理解,这种文件就是把文献信息分解为各个诸如titleauthor 等字段存储起来,方便编译文档时将各个字段按所需格式组合的一种“数据库”。为了更直观地理解它,我们在百度学术上找到一篇文章,然后点击引用,再点击BibTex 按钮。

下载一篇文献的.bib 信息

打开的网页会显示如下信息:

@article{赵俊华2017面向能源系统的数据科学,
  title={面向能源系统的数据科学:理论、技术与展望},
  author={赵俊华 and 董朝阳 and 文福拴 and 薛禹胜},
  journal={电力系统自动化},
  volume={41},
  number={4},
  pages={1-11},
  year={2017},
}

这就是关于一篇文章的信息了。将其保存在.bib 格式的纯文本文件中,即可以供我们接下来使用。参考文献变多时,可以继续在后面粘贴信息,当然最高效的方法是使用Endnote、Papers、Zotero 等文献管理软件一次性导出包含所有文献信息的.bib 文件。

拥有了一个.bib 文件后,把它放到和.Rmd 文件的同一位置(即R 项目的工作目录),然后只需要在.Rmd 文件头部添加bibliography 字段即可:

# 其他字段
bibliography: myref.bib

参考文献格式——.csl 文件

到目前为止,我们只是有了文献的数据库,并没有规定其排版所用的格式。我们需要一种.csl 格式的文件来制定版式,这是一种专门用来排版参考文献格式的文件。在GitHub 的这个项目 或是Zoreto 的这个页面上,都有做好的.csl 文件列表,包括了大量期刊模板或标准,下载即可用。如果真的找不到你想要的,可以学习一下如何自定义.csl 也可以。我们这里以Chinese 为关键词,搜索并下载一个中文论文常用的GB/T 7714-2015 格式的文件,放到.Rmd 所在的目录下,并在.Rmd 文档头部添加csl 字段即可:

csl: chinese-gb7714-2005-numeric.csl

插入参考文献

万事具备,现在可以在文章中引用参考文献了。在正文中直接插入如下格式即可:

[@赵俊华2017面向能源系统的数据科学]

@ 符号后写上.bib 中该文献部分大括号中第一行的字符作为标识符,编译时即可找到这篇文献的信息。如果你觉得它太长了,删去后面的一些字也无妨,但不要和其他文献的标识重复。

在正文中引用参考文献

在实际使用中,可能会有一些文中不想引用,但需要在末尾的参考文献列表中列出的文献。这时需要在头部加入一个nocite 参数,并列出只需要在文末列表中出现的文献标识符。否则如果不做任何操作,即使文献信息被加入到.bib 文件之中,它也不会出现在文中的任何地方。

nocite: | 
  @item1, @item2

隐去一个引用,但保留在文末参考文献中

关于参考文献引用的配置相对简单,关于它的更多信息,可以参考官方的介绍

设置交叉引用

比起参考文献,交叉引用的设置略显麻烦。首先它不是Rmarkdown 的自带功能,而是包含在它的另一个衍生品bookdown 里。你可以在R 环境中运行install.packages("bookdown") 来安装它。顾名思义,bookdown是用来写“书”的,它支持输出PDF、Gitbook、EPUB、Word 文档等格式。不过说是用来写“书”,也并非如此绝对,它只是将一系列的.Rmd 文档连在一起然后输出一个分章节的完整文件,或者输出一个长文档,与此同时还带来了诸如交叉引用等更多的功能。

建立一个R 项目

使用bookdown 之前,为了使用方便,需要先在RStudio 中新建一个项目。点击File -> New Project,然后在弹出的对话框里选择新建文件夹、从现有文件夹或从版本控制软件中新建项目,选完即可。之后你的文件夹中就会多出一个.Rproj 文件,作为一个项目的启动文件,同时记录项目的一些配置。使用项目的好处是,RStudio 会在你开启项目时,自动设置好工作目录、工作环境等,也可以以项目为单位进行版本控制。而在这里是为了指定bookdown 作为build 工具(RStudio 的build 选项只为建立好的项目开启)。

新建一个R 项目

与单纯的Rmarkdown 项目不同,在bookdown 项目中,你可以同时放置多个.Rmd 文件,并以数字标号——如01-instruction.Rmd02-literature_review.Rmd等——以在编译文档时确定文件顺序。每个.Rmd 文件将被视为一章,以一级标题# 为章名。比较特殊的是index.Rmd,它将永远被最先执行,所以你也可以在这里设置常规.Rmd 文档的头部参数,在其他文档中专心撰写内容。(你也可以通过设置自定义文档顺序,或者干脆只写一个.Rmd文档也无妨,详细可以查看官方介绍,这里不做赘述。)

bookdown 下的文档结构

bookdown 项目的头部参数设置

与单独的.Rmd 文件不同,bookdown 项目的头部YAML 设置信息只需要在第一个被执行的.Rmd 文件中完成,后续的文件不需要再写。设置bookdown 项目的头部时,有三个关键参数需要注意。

  • 首先要设置一个site: "bookdown::bookdown_site",该参数保证编译时RStudio 会调用正确的命令
  • 另外需要规定输出的文档类型如output: bookdown::pdf_book,参数值也可以是其他bookdown 下的文档类型,但要确保输出的是一个bookdown 包下的类;
  • 中文PDF 文档则需要在bookdown::pdf_book 下指定两个二级参数,latex_engine: xelatextemplate: <template file name> ,用以确定文档可以正确编译中文。这个template 文件在bookdown 开发者的bookdown 中文书籍范例 中可以找到。将文件放到项目下,再将template 参数的值设为该文件的路径。

这一部分整体的参数设置为:

site: "bookdown::bookdown_site"
output: 
    bookdown::pdf_book:
        latex_engine: xelatex
        template: <template file name>

如果你的output 选项下的配置过多,可以单独放进一个_output.yml 文件里并把它放在项目根目录下,效果相同。对于PDF 以外其他格式文档的输出,不需要指定latex_enginetemplate,可以针对其自己的格式选定其需要的二级参数,详见这里

设置build tools

设置好头部信息后,就可以设置RStudio 的build tools 了。在菜单栏中选择Build -> Configure Build Tools...,然后在弹出的对话框中,更改Project build tools 为Website,Book output format(s) 中找到你想输出的文档类,例子中是bookdown::pdf_book(注意,头部参数设置好之后,这一选项才会出现)。接下来,在RStudio 中的Enveroment 栏的右边位置会出现一个Build 栏,点击Build Book(或显示为Build Website),即可开始文档编译。输出的文档会出现在根目录下的_book/ 文件夹中。

配置Build Tools

交叉引用

配置做好之后,终于可以愉快地使用交叉引用了。bookdown 支持的交叉引用种类繁多,包括图片、表格、公式、定理、章节等等。

我们已经知道,Rmarkdown 中可以直接执行代码块绘制出图片和表格,并且每个代码块可以设置一个lable,在正文中引用这个图或表时,基本格式便是\@ref(<prefix>:lable),只是需要在的lable 前添加指定这个引用对象类型的前缀,比如引用图片,使用\@ref(fig:lable),表格使用\@ref(tab:lable) 等。

图片

使用代码绘制图片时,我们可以先使用如下的代码块设置:

```{r figureLable, fig.cap='test_figure'}
# code for figure.
```

然后在中文中输入\@ref(fig:figureLable),文档编译时就可以自动出现图片编号。而这里的fig.cap 则是图片的标题,也会被自动追加“图1” 等题注

图片的交叉引用

表格

同理,可以在文档中生成表格并且在正文中进行引用,只要正确设置了代码部分的lable 并在引用部分使用\@ref(tab:lable) 的格式。值得一提的是,如果你运行的是R 代码,bookdown 推荐使用knitr 包中的kable() 函数输出一些简单的表格,以获得更好的显示效果。结果如下图中的例子所示:

表格的交叉引用

公式

在书写公式时,因为使用简便的$$ 公式块不能正常地插入标签用于正文的引用,需要使用一个LaTeX 代码块,在公式末尾加入(\#eq:lable),在正文的引用中使用与上面相同的格式\@ref(eq:lable)。例如:

\begin{equation} 
  f\left(k\right) = \binom{n}{k} p^k\left(1-p\right)^{n-k}
  (\#eq:binom)
\end{equation}

然后在文中使用\@ref(eq:binom) 引用即可。

公式的交叉引用

定理

书写定理相对而言更简单,与在Markdown 中书写代码块类似,但是加上一个{theorem},并可以在大括号中规定标签等属性:

```{theorem, yourLable, name="the name of the theorem"}
# theorem 的内容
```

其中name 是定理被打印在文中时的名称。引用时,使用\@ref(thm:yourLable),效果达成。

定理的交叉引用

theorem 类似的环境及对应的前缀很多,可以翻看官方的这页说明

章节

我们已经说过,在bookdown 当中,一级标题被视为一个章节,在某个一级标题后加上{#lable},即可以在正文中使用\@ref(lable) 来引用它。注意这里不需要使用任何的前缀名,直接写lable 名称进行引用即可。不过引用章节时需要保证章节标号是开启的(头部没有设置number_section: false),否则将会无效。

引用某一章节

题注的本地化

如果你发现自己图表的输出结果是“Figure 1”,而不是想要的“图 1”, 你需要针对这些题注标签进行自定义。LaTeX 中的一些包通常会自动完成这些事,但输出Word 文档等其他文档时就需要自己来了。

在根目录下新建一个_bookdown.yml 文件,设定一个language 参数,并在下面设置自己需要的标签,如:

language:
  label:
    fig: "图 "
    tab: "表 "
    eq: "公式 "

二级设置下的label即为对题注标签的自定义选项。更多的标签设置可见文档说明

bookdown 所支持的交叉引用还是比较多的,但基本格式均类似,篇幅所限这里就不再举例。另外一提,无论引用的部分是在整个项目中的哪个.Rmd 文档中,都不妨碍在其他文件中引用它。

关于bookdown 的更多功能与自定义设置,例如其他的自定义选项、输出其他格式文档的细节设置等,感兴趣的读者可以直接翻阅其官方文档。你也可以参考上面提到的bookdown 中文书籍范例,针对范例对比查看。

尾巴

解决了参考文献和交叉引用的Rmarkown,在学术写作上又向前迈进了一步。读到这里,或许你会问,为了完成一点简单的任务做这么多配置,实在是大费周章;或是,这么麻烦,为什么不用LaTeX 直接写呢?比起Word 排版的糟心,我还是愿意折腾一下然后用Markdown 写文章;而比起直接上LaTeX,它还是更简单、轻便一点。如果实在是想要使用LaTeX,毕竟Rmarkdown 里可以直接运行LaTeX 代码,再不行还可以用R Sweave 文件直接写LaTeX 然后在里面运行R 或许其他程序的代码。如果再碰上只收Word 文档的情况,用Markdown 还是比直接在Word 里写东西舒服得多。更多的工具不应该带来更多的争论,而应该是更多的选择:)