Здесь есть две отдельные, хотя и связанные проблемы:
- Как программно процитировать пакет
- Как иметь два отдельных справочных раздела в документе уценки
Существуют решения для них обоих, которые я go расскажу по очереди:
Как программно процитировать пакет
Ключом здесь является понимание того, что Pando c запишет ваш документ только после фрагментов кода R. Это дает вам возможность писать файл .bib
программно как часть вашего документа по разметке R, который читается только Pando c на этапе создания документа.
Это также зависит от возможности использования два .bib
файла в вашей библиографии. Это также возможно, но мы пока оставим эту проблему.
Вам нужна функция, которая будет принимать имена пакетов, получать цитаты в формате bibtex, вставлять их все вместе и сохранять как .bib
файл. Я написал пример функции здесь, чтобы показать, как это можно сделать.
Эта функция должна обрабатывать пакеты, которые выдают несколько ссылок на bibtex, и автоматически вставляет имя пакета в bibtex, чтобы вы могли ссылаться на любой пакет в вашей уценке с помощью @packagename. Он использует нестандартную оценку и аргументы ...
, поэтому вам не нужно заключать в кавычки имена пакетов или заключать их в 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")
}
Чтобы использовать его, вы просто помещаете его в блок R с echo = FALSE и сделайте это:
citeR(dplyr, ggplot2, knitr, pROC)
Как получить два справочных раздела
Я не могу взять кредит на эту часть ответа, которую я получил с здесь . Это более сложный, чем первая часть. Прежде всего, вы должны использовать фильтр lua, для этого требуются самые последние версии rmarkdown и Pando c, поэтому обновите до последних версий, иначе это может не сработать .
Обоснование фильтра lua описано в предоставленной ссылке, но я включу его здесь с полным подтверждением @tarleb. Вы должны сохранить следующий файл как multiple-bibliographies.lua
в том же каталоге, что и уценка:
-- 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,}
}
Чтобы это работало, ваш заголовок YAML должен выглядеть следующим образом:
---
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
---
Обратите внимание, что packages.bib
не должно существовать, когда вы начинаете вязать документ, поскольку он будет создан до вызова Pando c.
Чтобы вставить разделы со ссылками, вам нужно поместить эти html фрагменты в соответствующих точках вашей уценки:
<div id = "refs_normal"></div>
и
<div id = "refs_software"></div>
Собираем все вместе
Я знаю, что это уже длинный ответ, но я подумал, что было бы хорошо включить полный рабочий пример и показать вывод в формате pdf:
---
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)
```#
и test.pdf выглядит так:
![enter image description here](https://i.stack.imgur.com/NECdV.png)
Если вы предпочитаете автоматически ссылаться на любые пакеты, которые вы используете, вы можете программно соскоблить имена с любых вызовов library()
в вашем документе уценки. Поскольку рабочий процесс для достижения вашей цели немного запутан, вы можете рассмотреть возможность создания небольшого пакета с функцией citeR
, документом lua и собственной функцией get_lib_citations_from_library_calls("my_markdown.Rmd")
, которая автоматизирует все это.