Embedding a beamer presentation in a regular document with RMarkdown

孤人 提交于 2020-01-24 21:32:47

问题


My aim is write a document in markdown (rmarkdown, more specifically), that can be compiled both to a regular PDF (or other) file and a beamer presentation at the same time, from the same source. (Using knitr.) Scenario: the document includes, in addition to the regular text, one sentence summaries for each paragraph and these should go to the presentation as the bullet points.

I know that I can compile a document to several different output formats at the same time with knitr, but the problem here is something else: the content of the document. How to include those sentences...? I must mark them somehow, and achieve that they're not compiled into the regular PDF, and at the same time only they should be compiled into the beamer presentation!

What's the solution here?

(I'm planning to do this with bookdown, but I have the feeling that it doesn't matter.)


回答1:


You could use the beamerarticle package to build an article class document from the beamer sources. I couldn't convince rmarkdown to build both documents at the same time, but the following works with alternating the header between the lines for the beamer output and the article document and renaming the output file in between:

---
output: 
  beamer_presentation:
    keep_tex: true
#  pdf_document: 
#    includes:
#      in_header: preamble.tex
---

sentence in both documents

``` {=latex}
\only<article>{
  sentence only in the article
}
```

``` {=latex}
\only<presentation>{
  sentence only in the presentation
}
```

With preamble.tex:

\usepackage{beamerarticle}

Complete rstudio project: https://rstudio.cloud/project/725309




回答2:


I finally managed to put together an approach which is working - I believe - perfectly, although it has some not-really-elegant solutions, and therefore there is very likely (a lot of) room for improvement.

The basic idea is to include margin notes, both in HTML and PDF, and then these margin notes are those that will be displayed in the presentation. So they serve two purpose: a quick summary of the paragraph (somewhat Tufte-style) and the basis for creating the presentation.

The presentation comes only in one format, there is no incremental version, where bullet points appear one-by-one. (Actually, there are no more bullet points at all, texts are simply displayed as sentences in different paragraphs.)

To achieve this, I used the custom block function of bookdown:

    Text

    ```{block, type="handout"}
    Margin note
    ```

    Text

Here are the details:

  • When compiling to HTML, the custom block conveniently compiles into a div, with appropriate type, so all we have to do is the format it in the CSS file:
p {
  text-align: justify;
  width: 80%;
  margin-left: 0;
  margin-right: 20%;
}
li:not(.chapter) {
  text-align: justify;
  width: 80%;
  margin-left: 0;
  margin-right: 20%;
}
.handout {
  float: right;
  clear: right;
  width: 18%;
  margin-top: 0.5rem;
  margin-bottom: 1rem;
  font-size: 1.1rem;
  line-height: 1.3;
  vertical-align: baseline;
  position: relative;
}
.handout p {
  font-size:100%;
  line-height:1.3;
  -webkit-hyphens: auto;
  -ms-hyphens: auto;
  hyphens: auto;
}
  • When compiling into PDF, we unfortunately get an environment, but we can use the environ package to turn it to a single - marginnote - command:
\NewEnviron{handout}{\marginnote{\footnotesize \BODY}[0.23cm]}
  • When compiling to beamer, things get a bit trickier. I found a similar solution which uses preprocessor. Instead of that, I've chosen to use Pandoc's filters. Luckily, we even have an example that is quite close to what we want! We will use a lua filter, however, a few things should be tuned...

  • First, documentclass is set "globally" (in index.Rmd) to book which won't work with beamer. Thus, in both beamer formats, we have to reset it:

function Meta(m)
  if FORMAT=="beamer" then m.documentclass="beamer" end
  return m
end
  • Next, we should crop out everything, except the marginnotes and the figures. The former is recognized by looking for RawBlock type with tex format which contains the text handout, the latter needs some tweaking. Albeit it is a completely unrelated issue, here are the details: the part of the filter that recognizes the Image part should also be modified to work with Rmarkdown generated files: (el.t == "Para" and el.c[1].t == "Image") or. More importantly, even this won't work if we use fig.align or something like that as it changes the generated markdown's format from ![]() to direct LaTeX code. So we have to add another condition: (el.t == "RawBlock" and el.format == "tex" and string.match( el.text, "includegraphics" ) ) or. Overall, here is the second part of the lua filter:
function Pandoc(doc)
    if FORMAT=="beamer" then
      local hblocks = {}
      for i,el in pairs(doc.blocks) do
          if (el.t == "Div" and el.classes[1] == "handout") or
             (el.t == "BlockQuote") or
             (el.t == "RawBlock" and el.format == "tex" and string.match( el.text, "includegraphics" ) ) or
             (el.t == "RawBlock" and el.format == "tex" and string.match( el.text, "handout" ) ) or
             (el.t == "OrderedList" and el.style == "Example") or
             (el.t == "Para" and el.c[1].t == "Image") or
             (el.t == "Header") then
             table.insert(hblocks, el)
          end
      end
      return pandoc.Pandoc(hblocks, doc.meta)
    end
end
  • The fact that we don't cut out the handout environment means that we have to do something with it, we simply translate it to text:
\NewEnviron{handout}{\BODY}
  • We still have to be careful to break long slides. Luckily, there is an allowframebreaks option in beamer (which is considered evil, but I think here it is completely justified, or rather, we don't have any better solution); the only problem is that we can't add it to each slide, as we have no direct control on the LaTeX code for the frames. Luckily, there's a solution to modify the option in header to make it default, and we can easily do it in preamble.tex. I combine this solution with a more elegant numbering scheme:
\let\oldframe\frame
\renewcommand\frame[1][allowframebreaks]{\oldframe[#1]}
\makeatletter
\defbeamertemplate*{frametitle continuation}{only if multiple}{%
    \ifnum \numexpr \beamer@endpageofframe+1-\beamer@startpageofframe\relax > 1
        \insertcontinuationcount.%
    \fi
}
\makeatother
  • The most non-elegant part is that we can't include the beamer_presentation output to twice, and with different names, or at least I don't know a solution for this so we have to manually compile it with bookdown::render_book and don't forget to rename (and move) the resulting compiled file afterwards.

  • This also means that we have to give up using the Build Book button, unfortunately. We rather have to create a script to do all what the button would (and I hope that I made no mistake, and it is indeed doing the same as the button...):

bookdown::render_book( "index.Rmd", "bookdown::pdf_book" )
bookdown::render_book( "index.Rmd", "bookdown::gitbook" )
bookdown::render_book( "index.Rmd", "bookdown::epub_book" )
bookdown::render_book( "index.Rmd", "beamer_presentation" )
file.rename( "FerenciTamas_ValszamEsStatAlapvonalai.pdf", "./docs/FerenciTamas_ValszamEsStatAlapvonalai_handout.pdf" )
  • Finally, we also need a custom Pandoc template, as for the presentation it is easily possible that we need a short title (which is not currently supported by Pandoc). So I changed \title{$title$$if(thanks)$\thanks{$thanks$}$endif$} to \title[$if(short-title)$$short-title$$endif$]{$title$$if(thanks)$\thanks{$thanks$}$endif$} (adding a short-title element to index.Rmd).

  • It's again an unrelated issue, but I also changed the \frame{\sectionpage} line in \AtBeginSection to

\begin{frame}{$toc-title$}
    \tableofcontents[currentsection]
\end{frame}

which is of course mostly a matter of taste, but an objective reason is that it works in non-English languages as well (the original template would display "Section 1" even if non-English language is selected).

And that's it!

You can find everything put together, in a completely realized project here: https://github.com/tamas-ferenci/FerenciTamas_ValszamEsStatAlapvonalai.

Of course, I really welcome any feedback, criticism or suggestion on improvement.



来源:https://stackoverflow.com/questions/58885889/embedding-a-beamer-presentation-in-a-regular-document-with-rmarkdown

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!