作为简单、易懂的纯文本语言,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
文件。简单地理解,这种文件就是把文献信息分解为各个诸如title
、author
等字段存储起来,方便编译文档时将各个字段按所需格式组合的一种“数据库”。为了更直观地理解它,我们在百度学术上找到一篇文章,然后点击引用,再点击BibTex 按钮。
打开的网页会显示如下信息:
@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 选项只为建立好的项目开启)。
与单纯的Rmarkdown 项目不同,在bookdown 项目中,你可以同时放置多个.Rmd
文件,并以数字标号——如01-instruction.Rmd
、02-literature_review.Rmd
等——以在编译文档时确定文件顺序。每个.Rmd
文件将被视为一章,以一级标题#
为章名。比较特殊的是index.Rmd
,它将永远被最先执行,所以你也可以在这里设置常规.Rmd
文档的头部参数,在其他文档中专心撰写内容。(你也可以通过设置自定义文档顺序,或者干脆只写一个.Rmd
文档也无妨,详细可以查看官方介绍,这里不做赘述。)
bookdown 项目的头部参数设置
与单独的.Rmd
文件不同,bookdown 项目的头部YAML
设置信息只需要在第一个被执行的.Rmd
文件中完成,后续的文件不需要再写。设置bookdown 项目的头部时,有三个关键参数需要注意。
- 首先要设置一个
site: "bookdown::bookdown_site"
,该参数保证编译时RStudio 会调用正确的命令 - 另外需要规定输出的文档类型如
output: bookdown::pdf_book
,参数值也可以是其他bookdown 下的文档类型,但要确保输出的是一个bookdown 包下的类; - 中文PDF 文档则需要在
bookdown::pdf_book
下指定两个二级参数,latex_engine: xelatex
和template: <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_engine
和template
,可以针对其自己的格式选定其需要的二级参数,详见这里。
设置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/
文件夹中。
交叉引用
配置做好之后,终于可以愉快地使用交叉引用了。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 里写东西舒服得多。更多的工具不应该带来更多的争论,而应该是更多的选择:)