How to get a second bibliography?
Asked Answered
W

1

14

In rmarkdown PDF and HTML I want two bibliographies—one for papers/books, and one for software I have used in my research. I found this related issue but it doesn't answer my question since it's concerning the combination of two *.bib files into one bibliography.

I'm used to place my bibliography with <div id="refs"></div> as explained here. Possibly a second one can be placed similarly with <div id="refs_2"></div>, but I couldn't figure out how to do it since this "refs" seems not to be defined anywhere.

I usually define the software in the YAML header like this

nocite: |
    @xie_knitr:_2018, @allaire_rmarkdown:_2018, @rstudio_team_rstudio:_2016, 
    @r_development_core_team_r:_2018

so I don't have to constantly copy-paste it into the *.bib-file every time (which works well with one bibliography). Ideally this nocite:-list would appear as a new bibliography titled "Software" below the other, but I also would be happy with a two *.bib-file solution.

The expected output would be something like this:

enter image description here

Has anybody done this before and could explain how to do this?

Wein answered 7/4, 2018 at 12:16 Comment(1)
I looked into doing something similar previously (wish I had posted it on Stackoverflow now as it is a great question). From my experience your best option is to look into a LaTeX solution, as I don&#39;t think pandoc-citeproc has the capacity to do this. Hope to get time to help find a proper RMarkdown solution as I never got anything to work in the past.Breviary
P
14

This isn't entirely trivial, but possible. The following uses pandoc Lua filters and a function available in pandoc 2.1.1 and later. You'll have to upgrade to a recent version to make it work.

Using the filter works by adding this to your document's YAML section:

---
output:
  bookdown::html_document2:
    pandoc_args: --lua-filter=multiple-bibliographies.lua
bibliography_normal: normal-bibliography.bib
bibliography_software: software.bib
---

Then add divs to mark where the bibliographies are supposed to be included in the document.

# Bibliography

::: {#refs_normal}
:::

::: {#refs_software}
:::

Each refsX div should have a matching bibliographyX entry in the header.

The Lua Filter

Lua filters allow to modify the document programmatically. We use this to generate the reference section separately. For each div that looks like it is supposed to contain references (i.e., whose ID is refsX, with X being empty or the name of your topic), we create temporary dummy documents which contain all citations and the reference div, but where bibliography is set to the value of bibliographyX. This allows us to create the bibliography for each topic while ignoring all other topics (as well as the main bibliography).

The aforementioned step doesn't resolve the citations in the actual document, so we need to do this separately. It is enough to fold all bibliographyX into the bibliography meta value and the run pandoc-citeproc on the full document.

-- 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,}
}

I published the filter as part of the officially supported Lua filters collection. See there for a more complete, up-to-date version which also respects csl and nocite settings.

For more info and details on Lua filters, see the R Markdown docs.

Pusillanimity answered 9/4, 2018 at 14:45 Comment(6)
The lua file doesn't work on my computer. It returns an error message: ``` Error running filter multiple-bibliographies.lua: PandocFilterError "pandoc-citeproc" "Could not find executable pandoc-citeproc" stack traceback: multiple-bibliographies.lua:38: in function <multiple-bibliographies.lua:28> Error: pandoc document conversion failed with error 83 Execution halted ```Anamorphism
Try the updated filter linked in the answer.Pusillanimity
Hi, using the updated link, I get the error Error running filter multiple-bibliographies.lua: PandocFilterError "pandoc" "Could not find executable pandoc" stack traceback: multiple-bibliographies.lua:50: in upvalue 'run_citeproc' multiple-bibliographies.lua:82: in function <multiple-bibliographies.lua:68>. Any idea what's happening here?Lob
Seems like a problem with the system's PATH variable. But good alternative: get the latest pandoc and use local function run_citeproc(doc, quiet) return pandoc.utils.citeproc(doc) endPusillanimity
Thanks for getting back to me! Updating to the latest pandoc (without changing anything else) made the error go away, but then no bibliography rendered. As for the code, do you mean to just replace that existing line with this code?Lob
Huh, interesting. Don't know why that happens. Maybe replacing the complete run_citeproc function with above code will fix it.Pusillanimity

© 2022 - 2024 — McMap. All rights reserved.