问题描述
我想引用一个项目中使用的 R 包,但由于它们相当多,我认为创建两个单独的参考部分是个好主意:一个包含我特定领域的引用,一个包含引用对于 R 包.
我的第一个想法是检查我是否可以在 .bib 文件中一次导出所有使用的包的引用,但我不确定 R Markdown 可以处理 .bib 文件和论文参考书目特定于我的域和 R 包的 .bib 文件.
由于函数 citation()
或 toBibtex()
生成 Bibtex 引文,我认为有可能用这些函数生成专用于 R 包的参考部分直接在 .Rmd 文件中.但是,当这些命令包含在带有 R Markdown 的块中时,似乎不可能自动格式化引用.
这是我正在尝试做的事情的可重现示例:
---标题:引用 R 包"作者: ""日期:01/02/2020"输出:pdf_document参考书目:test.bib---这是一篇论文的引用:@mayer2011.# 参考书目 {-}\setlength{\parindent}{-0.2in}\setlength{\leftskip}{0.2in}\无缩进<div id="refs"></div>```{r refmgr 引用,结果=asis",echo=FALSE}# 打印``\setlength{\parindent}{0in}\setlength{\leftskip}{0in}\setlength{\parskip}{0pt}# R 包的参考书目 {-}```{r}引文(dplyr")toBibtex(引文(dplyr"))``
这里是test.bib
的内容:
@article{mayer2011,title = {{{CEPII}} 的 {{Distances Measures}} 注释:{{GeoDist 数据库}}},shorttitle = {{{CEPII}} 的 {{Distances Measures}}} 的注释,期刊 = {SSRN 电子期刊},doi = {10.2139/ssrn.1994531},作者 = {Mayer, Thierry and Zignago, Soledad},年 = {2011}}
知道如何在单独的参考部分中轻松包含 R 包的引用吗?
见
如果您希望自动引用您使用的任何包,您可以通过编程从 Markdown 文档中对 library()
的任何调用中抓取名称.由于实现目标的工作流程有点复杂,您可能需要考虑使用 citeR
函数、lua 文档和您自己的 get_lib_citations_from_library_calls("my_markdown.Rmd") 创建一个小包
函数可以自动执行所有这些操作.
I would like to cite the R packages used in a project but since they are quite numerous, I think it would be a good idea to create two separate reference sections: one with the references of my specific domain and one with the references for the R packages.
My first idea would be to check if I can export all the citations of the packages used at once in a .bib file, but I'm not sure that R Markdown can handle both the .bib file with the bibliography of papers specific to my domain and the .bib file for the R packages.
Since the functions citation()
or toBibtex()
generate Bibtex citations, I thought it might be possible to generate the reference section dedicated to the R packages with these functions directly in the .Rmd file. However, it does not seem possible to automatically format a reference when these commands are included in a chunk with R Markdown.
Here's a reproducible example of the thing I'm trying to do:
---
title: "Cite R packages"
author: ""
date: "01/02/2020"
output: pdf_document
bibliography: test.bib
---
This is a citation of a paper: @mayer2011.
# Bibliography {-}
\setlength{\parindent}{-0.2in}
\setlength{\leftskip}{0.2in}
\noindent
<div id="refs"></div>
```{r refmgr references, results="asis", echo=FALSE}
# Print
```
\setlength{\parindent}{0in}
\setlength{\leftskip}{0in}
\setlength{\parskip}{0pt}
# Bibliography for R packages {-}
```{r}
citation("dplyr")
toBibtex(citation("dplyr"))
```
and here's the content of test.bib
:
@article{mayer2011,
title = {Notes on {{CEPII}}'s {{Distances Measures}}: {{The GeoDist Database}}},
shorttitle = {Notes on {{CEPII}}'s {{Distances Measures}}},
journal = {SSRN Electronic Journal},
doi = {10.2139/ssrn.1994531},
author = {Mayer, Thierry and Zignago, Soledad},
year = {2011}
}
Any idea about how to easily include the references of the R packages in a separate reference section?
EDIT: see here for another solution.
There are two seperate though related problems here:
- How to cite a package programatically
- How to have two seperate reference sections in your markdown document
There are solutions to both of them which I'll go over in turn:
How to cite a package programatically
The key here is realising that Pandoc will only write your document after the R code chunks have run. This gives you the opportunity of writing a .bib
file programatically as part of your R markdown document, which is only read by Pandoc at the document creation stage.
It also depends on being able to use two .bib
files in your bibliography. This is also possible, but we'll leave that issue for now.
What you need is a function that will take package names, get the bibtex-formatted citations, paste them all together and save them as a .bib
file. I have written an example function here to show how that could be done.
This function has to handle packages that spit out multiple bibtex citations, and it will automatically insert the package name in bibtex so that you can reference any package in your markdown with @packagename. It uses non-standard evaluation and the ...
arguments so that you don't need to quote the package names or wrap them in c()
:
citeR <- function(...)
{
packages <- unlist(lapply(as.list(match.call()), deparse))[-1]
Rbibs <- ""
for(package in packages)
{
Rbib <- capture.output(print(citation(package), bibtex = T))
Rbib <- mapply(function(x, y) Rbib[x:y],
grep(" @.+[{]", Rbib),
which(Rbib == " }"))
if(class(Rbib) == "matrix"){
Rbib[1, 1] <- gsub(",", paste0(package, ","), Rbib[1, 1])
Rbib <- paste0(Rbib, collapse = "\n")
} else {
Rbib <- unlist(lapply(Rbib, function(x) {
x[1] <- gsub(",", paste0(package, ","), x[1]);
x <- paste0(unlist(x), collapse = "\n")
return(x)
}))
}
if(length(Rbib) > 1) {
if(any(grepl("@Manual", Rbib))) {
Rbib <- Rbib[grep("@Manual", Rbib)][1]
} else {
Rbib <- Rbib[1]}}
Rbibs <- paste(Rbibs, Rbib, sep = "\n\n")
}
writeBin(charToRaw(utf8::as_utf8(Rbibs)), "packages.bib")
}
To use it you would just put it in an R chunk with an echo = FALSE and do this:
citeR(dplyr, ggplot2, knitr, pROC)
How to have two reference sections
I cannot take credit for this part of the answer, which I got from here. It is more involved than the first part. First of all, you must use a lua filter, and this requires the most up to date versions of rmarkdown and Pandoc so please update to the lastest versions or this may not work.
The rationale for the lua filter is described in the provided link, but I will include it here with full acknowledgement to @tarleb. You must save the following file as multiple-bibliographies.lua
in the same directory as your markdown:
-- file: multiple-bibliographies.lua
--- collection of all cites in the document
local all_cites = {}
--- document meta value
local doc_meta = pandoc.Meta{}
--- Create a bibliography for a given topic. This acts on all divs whose ID
-- starts with "refs", followed by nothings but underscores and alphanumeric
-- characters.
local function create_topic_bibliography (div)
local name = div.identifier:match('^refs([_%w]*)$')
if not name then
return nil
end
local tmp_blocks = {
pandoc.Para(all_cites),
pandoc.Div({}, pandoc.Attr('refs')),
}
local tmp_meta = pandoc.Meta{bibliography = doc_meta['bibliography' .. name]}
local tmp_doc = pandoc.Pandoc(tmp_blocks, tmp_meta)
local res = pandoc.utils.run_json_filter(tmp_doc, 'pandoc-citeproc')
-- first block of the result contains the dummy para, second is the refs Div
div.content = res.blocks[2].content
return div
end
local function resolve_doc_citations (doc)
-- combine all bibliographies
local meta = doc.meta
local orig_bib = meta.bibliography
meta.bibliography = pandoc.MetaList{orig_bib}
for name, value in pairs(meta) do
if name:match('^bibliography_') then
table.insert(meta.bibliography, value)
end
end
doc = pandoc.utils.run_json_filter(doc, 'pandoc-citeproc')
doc.meta.bibliography = orig_bib -- restore to original value
return doc
end
return {
{
Cite = function (c) all_cites[#all_cites + 1] = c end,
Meta = function (m) doc_meta = m end,
},
{Pandoc = resolve_doc_citations,},
{Div = create_topic_bibliography,}
}
To get this to work, your YAML header should look like this:
---
title: "Cite R packages"
author: ''
date: "01/02/2020"
output:
pdf_document:
pandoc_args: --lua-filter=multiple-bibliographies.lua
bibliography_software: packages.bib
bibliography_normal: test.bib
---
Note that packages.bib
doesn't need to exist when you start knitting the document, since it will be created before Pandoc is called.
To insert the references sections, you need put these html snippets at the appropriate points of your markdown:
<div id = "refs_normal"></div>
and
<div id = "refs_software"></div>
Putting it all together
I know this is already a long answer, but I thought it would be good to include a full working example and show the pdf output:
---
title: "Cite R packages"
author: ''
date: "01/02/2020"
output:
pdf_document:
pandoc_args: --lua-filter=multiple-bibliographies.lua
bibliography_software: packages.bib
bibliography_normal: test.bib
---
This is a citation of a paper: @mayer2011.
This is a citation of an R package @dplyr
And another @ggplot2 and another @knitr plus @pROC
# Bibliography{-}
\setlength{\parindent}{-0.2in}
\setlength{\leftskip}{0.2in}
\noindent
<div id = "refs_normal"></div>
\setlength{\parindent}{0in}
\setlength{\leftskip}{0in}
\setlength{\parskip}{0pt}
# Software used{-}
\setlength{\parindent}{-0.2in}
\setlength{\leftskip}{0.2in}
\noindent
<div id = "refs_software"></div>
\setlength{\parindent}{0in}
\setlength{\leftskip}{0in}
\setlength{\parskip}{0pt}
```{r citeR, echo=FALSE}
citeR <- function(...)
{
packages <- unlist(lapply(as.list(match.call()), deparse))[-1]
Rbibs <- ""
for(package in packages)
{
Rbib <- capture.output(print(citation(package), bibtex = T))
Rbib <- mapply(function(x, y) Rbib[x:y],
grep(" @.+[{]", Rbib),
which(Rbib == " }"))
if(class(Rbib) == "matrix")
{
Rbib[1, 1] <- gsub(",", paste0(package, ","), Rbib[1, 1])
Rbib <- paste0(Rbib, collapse = "\n")
}
else
{
Rbib <- unlist(lapply(Rbib, function(x) {
x[1] <- gsub(",", paste0(package, ","), x[1]);
x <- paste0(unlist(x), collapse = "\n")
return(x)
}))
}
if(length(Rbib) > 1)
{
if(any(grepl("@Manual", Rbib)))
{
Rbib <- Rbib[grep("@Manual", Rbib)][1]
}
else
{
Rbib <- Rbib[1]
}
}
Rbibs <- paste(Rbibs, Rbib, sep = "\n\n")
}
writeBin(charToRaw(utf8::as_utf8(Rbibs)), "packages.bib")
}
citeR(dplyr, ggplot2, knitr, pROC)
```#
and test.pdf looks like this:
If you would rather automatically cite any packages you use, you could programatically scrape the names from any calls to library()
in your markdown document. Since the workflow for achieving your goal is a little convoluted, you might want to consider creating a small package with the citeR
function, the lua document and your own get_lib_citations_from_library_calls("my_markdown.Rmd")
function that automates all of this.
这篇关于在 R Markdown 中使用 citation() 自动生成 R 包的参考书目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!