Tamas Ferenci
Tamas Ferenci

Reputation: 648

Embedding a beamer presentation in a regular document with RMarkdown

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.)

Upvotes: 1

Views: 1746

Answers (3)

tchevrier
tchevrier

Reputation: 1171

I am very excited about this discussion, because I still do need help and support as well. So I hope this will revive things, as I am obviously not the only one looking for such feature.

Unless I am mistaken, I provided an (elegant?) answer to your question here: creating accompanying slides for bookdown project.
Did you get a chance to see it? Does this not solve your question? It seems to me that I am doing exactly what you are trying to achieve (I checked your Github)
I just did a quick search in SO with tags beamer bookdown and my post came up first... not for you?

The solution is the one you hint at: create a bookdown project with several output types.
The one issue I did not manage to resolve is that i could not customize the book output filename (see comments following the SO question) - a pity - maybe a bookdown feature request? But YiHui Xie did not offer this as a suggestion - despite my hinting at it - you might ask again?
Then in an single click, you could get your pdf beamer slides, your pdf book, your html web book, your epub e-book - absolutely amazing, all thanks to XieYiHui. Now - instead - i just do need TWO clicks, because when I compile the slides and the pdf, it (over)writes to the same file (actually, it does not!! it first writes in the root folder, but then moves it inside the /_book folder and that's when the overwrite takes place - so my thought was this should be a very easy fix for YiHui Xie, but maybe not?).

Anyway, all this worked absolutely perfect, until John McFarlane decided to change the fundamentals of how Pandoc works and basically killed my approach. The discussion is here: Pandoc #4317 forces content under title slides to be included in a frame in pandoc > 2.7. To allow vertical slides in a pdf output - a total nonsense imho - they are forcing all contents ABOVE slide level onto a slide!! John McFarlane did try to see if he could help me, but invoked the argument that they did not think about my case and now he does not want to revert... He even asked me to post my question in his email list, but there were no takers to help... :-( so bottom line, my solution still works perfect, as long as I use pandoc < 2.7 (in Rstudio, just replace pandoc in the bin folder with an earlier version).

Summary: 2 things still needed for a perfect smooth solution:
1. bookdown: customize the output filename, just for convenience of one click solution
2. Obtaining from John McFarlane that Pandoc either does not force content onto slides randomly or allows to escape that unwanted behavior. That's crucial for being able to use current Pandoc version.

Upvotes: 0

Tamas Ferenci
Tamas Ferenci

Reputation: 648

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.

Upvotes: 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

Upvotes: 2

Related Questions