使用RMarkdown将投影仪演示文稿嵌入到常规文档中 [英] Embedding a beamer presentation in a regular document with RMarkdown
问题描述
我的目标是用markdown
(更具体地说是rmarkdown
)编写一个文档,该文档可以同时编译为常规PDF(或其他)文件和演示文稿.时间,来自同一来源. (使用knitr
.)场景:除常规文本外,文档还包括每个段落的一句话摘要,这些摘要应作为要点显示在演示文稿中.
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.
我知道我可以将文档编译为几种不同的格式knitr
同时输出格式,但是这里的问题是另外一个问题:文档的内容.如何包含这些句子...?我必须以某种方式标记它们,并实现将它们 not 编译为常规PDF,和,同时仅将它们编译进入投影仪演示!
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!
这里有什么解决方案?
(我打算用bookdown
来做到这一点,但我觉得没关系.)
(I'm planning to do this with bookdown
, but I have the feeling that it doesn't matter.)
推荐答案
我终于设法建立了一种可行的方法-我认为-完美,尽管它有一些不太优雅的解决方案,所以有很多可能(很大)的改进空间.
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.
基本思想是在HTML和PDF中都包括边距注释,然后这些边距注释就是将在演示文稿中显示的那些边距注释.因此,它们有两个目的:对该段的简要概述(某种Tufte风格)和创建演示文稿的基础.
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
以下是详细信息:
- 编译为HTML时,自定义块可以使用适当的
type
方便地编译为div
,因此我们要做的就是在CSS文件中设置其格式:
- When compiling to HTML, the custom block conveniently compiles into a
div
, with appropriatetype
, 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;
}
- 不幸的是,当编译为PDF时,我们得到了一个环境,但是我们可以使用
environ
包将其转换为单个-marginnote
-命令: - 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]}
-
当编译为
beamer
时,事情会变得有些棘手.我发现了一个类似的使用预处理器的解决方案.取而代之的是,我选择使用Pandoc的过滤器.幸运的是,我们甚至有一个示例非常接近我们想要的!我们将使用lua过滤器,但是,应调整一些内容...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...首先,将
documentclass
设置为全局"(在index.Rmd
中)为book
,这不适用于投影仪.因此,在两种投影仪格式中,我们都必须将其重置:First,
documentclass
is set "globally" (inindex.Rmd
) tobook
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
- 接下来,我们应该裁剪掉所有内容,除了旁注和数字.前者是通过查找包含文本
handout
的tex
格式的RawBlock
类型来识别的,而后者则需要进行一些调整.尽管这是一个完全不相关的问题,但这里有详细信息:识别图像部分的过滤器部分也应为.更重要的是,如果我们使用fig.align
或类似的东西,即使这样也将无法工作,因为它将生成的markdown格式从![]()
更改为直接LaTeX代码.因此,我们必须添加另一个条件:(el.t == "RawBlock" and el.format == "tex" and string.match( el.text, "includegraphics" ) ) or
.总的来说,这是lua过滤器的第二部分: - Next, we should crop out everything, except the marginnotes and the figures. The former is recognized by looking for
RawBlock
type withtex
format which contains the texthandout
, 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 usefig.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
- 我们没有删除
handout
环境的事实意味着我们必须对其进行处理,我们只需将其翻译为文本即可: - 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}
- 我们仍然必须小心折断长幻灯片.幸运的是,在Beamer中有一个
allowframebreaks
选项(这被认为是邪恶的,但我认为这里是完全有道理的,或者,我们没有更好的解决方案);唯一的问题是我们无法将其添加到每张幻灯片中,因为我们无法直接控制框架的LaTeX代码.幸运的是,有一个解决方案可以修改标头中的选项以使其默认,可以轻松地在preamble.tex
中执行此操作.我将此解决方案与更优雅的编号方案结合在一起: - 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 inpreamble.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
-
最不雅致的部分是,我们不能将
beamer_presentation
输出包含两次,并且名称不同,或者至少我不知道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 withbookdown::render_book
and don't forget to rename (and move) the resulting compiled file afterwards.不幸的是,这也意味着我们必须放弃使用
Build Book
按钮.我们宁愿创建一个脚本来完成按钮的所有操作(我希望我没有犯错,并且确实与按钮的操作相同...):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" )
-
最后,我们还需要一个自定义的Pandoc模板,因为对于演示文稿,我们很可能需要一个简短的标题(Pandoc目前不支持该标题).所以我将
\title{$title$$if(thanks)$\thanks{$thanks$}$endif$}
更改为\title[$if(short-title)$$short-title$$endif$]{$title$$if(thanks)$\thanks{$thanks$}$endif$}
(在index.Rmd
中添加了short-title
元素).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 ashort-title
element toindex.Rmd
).这又是一个不相关的问题,但我也将
\AtBeginSection
中的\frame{\sectionpage}
行更改为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}
这当然主要是出于品味的问题,但是客观原因是它也适用于非英语语言(即使选择了非英语语言,原始模板也会显示"Section 1").
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).
就是这样!
您可以在这里完全实现的项目中找到所有内容: https://github.com /tamas-ferenci/FerenciTamas_ValszamEsStatAlapvonalai .
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.
这篇关于使用RMarkdown将投影仪演示文稿嵌入到常规文档中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
-
- 接下来,我们应该裁剪掉所有内容,除了旁注和数字.前者是通过查找包含文本