forked from rstudio/rmarkdown-cookbook
-
Notifications
You must be signed in to change notification settings - Fork 0
/
09-multiformat.Rmd
421 lines (304 loc) · 18.8 KB
/
09-multiformat.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# Multiple Output Formats {#multi-formats}
One main advantage of R Markdown is that it can create multiple output formats from a single source, which could be one or multiple Rmd documents. For example, this book was written in R Markdown, and compiled to two formats: PDF for printing, and HTML for the online version.
Sometimes it can be challenging to make an output element of a code chunk work for all output formats. For example, it is extremely simple to create a rounded and circular image in HTML output with a single CSS rule (`img { border-radius: 50%; }`), but not so straightforward in LaTeX output (typically it will involve TikZ graphics).
Sometimes it is just impossible for an output element to work for all output formats. For example, you can easily create a GIF animation with the **gifski** package [@R-gifski] (see Section \@ref(animation)), and it will work perfectly for HTML output, but embedding such an animation in LaTeX output is not possible without extra steps of processing the GIF file and using extra LaTeX packages.
This chapter provides a few examples that can work for multiple formats. If a certain feature is only available to a specific output format, we will show you how to conditionally enable or disable it based on the output format.
## LaTeX or HTML output {#latex-html}
LaTeX and HTML are two commonly used output formats. The function `knitr::is_latex_output()`\index{knitr!is\_latex\_output()} tells you if the output format is LaTeX (including Pandoc output formats `latex` and `beamer`). Similarly, the function `knitr::is_html_output`\index{knitr!is\_html\_output()} tells you if the output format is HTML. By default, these Pandoc output formats are considered HTML formats: `markdown`, `epub`, `html`, `html4`, `html5`, `revealjs`, `s5`, `slideous`, and `slidy`. If you do not think a certain Pandoc format is HTML, you may use the `excludes` argument to exclude it, e.g.,
```{r, collapse=TRUE}
# do not treat markdown as an HTML format
knitr::is_html_output(excludes = 'markdown')
```
If a certain output element can only be generated in LaTeX or HTML, you can use these functions to conditionally generate it. For example, when a table is too big on a PDF page, you may include the table in an environment of a smaller font size, but such a LaTeX environment certainly will not work for HTML output, so it should not be included in HTML output (if you want to tweak the font size for HTML output, you may use CSS). Below is a full example:
`r import_example('latex-tiny.Rmd')`
The key in the above example is the chunk option `include = knitr::is_latex_output()`\index{chunk option!include}. That is, the environment `\begin{tiny} \end{tiny}` is only included when the output format is LaTeX. The two tables in the example will look identical when the output format is not LaTeX.
In Section \@ref(font-color), we used these functions to change the text color for HTML and LaTeX output. In Section \@ref(animation), we showed an animation example, which also used this trick. The code chunk that generated the animation for HTML output and static images for LaTeX output is like this:
````md
```{r animation.hook=if (knitr::is_html_output()) 'gifski'}`r ''`
for (i in 1:2) {
pie(c(i %% 2, 6), col = c('red', 'yellow'), labels = NA)
}
```
````
These conditional functions can be used anywhere. You can use them in other chunk options (e.g., `eval` for conditional evaluation of the chunk), or in your R code, e.g.,
````md
```{r, eval=knitr::is_html_output(), echo=FALSE}`r ''`
cat('You will only see me in HTML output.')
```
```{r}`r ''`
if (knitr::is_latex_output()) {
knitr::asis_output('\n\n\\begin{tiny}')
}
```
````
## Display HTML widgets {#html-widgets}
HTML widgets (<https://htmlwidgets.org>)\index{HTML!widgets} are typically interactive JavaScript applications, which only work in HTML output. If you knit an Rmd document containing HTML widgets to a non-HTML format such as PDF or Word, you may get an error message like this:
```md
Error: Functions that produce HTML output found in document
targeting X output. Please change the output type of this
document to HTML. Alternatively, you can allow HTML output in
non-HTML formats by adding this option to the YAML front-matter
of your rmarkdown file:
always_allow_html: yes
Note however that the HTML output will not be visible in
non-HTML formats.
```
There is actually a better solution than the one mentioned in the above error message, but it involves extra packages. You can install the **webshot** package [@R-webshot]\index{R package!webshot} in R and also install PhantomJS\index{PhantomJS}:
```{r, eval=FALSE}
install.packages('webshot')
webshot::install_phantomjs()
```
Then if you knit an Rmd document with HTML widgets to a non-HTML format, the HTML widgets will be displayed as static screenshots. The screenshots are automatically taken in **knitr**. [Section 2.10](https://bookdown.org/yihui/bookdown/html-widgets.html) of the **bookdown** book contains more information on finer control over the screenshots.
## Embed a web page {#include-url}
If you have the **webshot** package [@R-webshot]\index{R package!webshot} and PhantomJS\index{PhantomJS} installed (see Section \@ref(html-widgets)), you can embed any web page in the output document through `knitr::include_url()`\index{knitr!include\_url()}. When you pass a URL of a web page to this function in a code chunk, it will generate an `<iframe>` (inline frame)\index{HTML!iframe} if the output format is HTML, and a screenshot of the web page for other output formats. You can view the actual page in the inline frame. For example, Figure \@ref(fig:include-url) should show you my homepage if you are reading the online version of this book, otherwise you will see a static screenshot instead.
\let\ooldhref\href
\let\href\oldhref
```{r, include-url, out.width='100%', fig.cap="Embed Yihui's homepage as an iframe or screenshot.", dev='png', cache=TRUE, screenshot.opts=list(vwidth=992)}
knitr::include_url('https://yihui.org')
```
\let\href\ooldhref
Most chunk options related to figures also work for `knitr::include_url()`, such as `out.width` and `fig.cap`.
If you have published a Shiny app publicly on a server, you can use `knitr::include_app()`\index{knitr!include\_app()} to include it, which works in the same way as `include_url()`. [Section 2.11](https://bookdown.org/yihui/bookdown/web-pages-and-shiny-apps.html) of the **bookdown** book [@bookdown2016] contains more details about `include_app()` and `include_url()`.
## Multiple figures side by side {#figures-side}
You can place multiple figures side by side using the `fig.show="hold"`\index{chunk option!fig.show} along with the `out.width` option\index{chunk option!out.width}. In the example below, we have set `out.width="50%"` (see Figure \@ref(fig:figures-side) for the output):
`r import_example('figures-side.Rmd')`
```{r, child='examples/figures-side.Rmd', echo=FALSE, fig.dim=c(5, 4), fig.cap="Side-by-side figures."}
```
This simple approach works for both PDF and HTML output.
If you want to use sub-figures when there are multiple plots in a figure, you may see Section \@ref(latex-subfigure), but please note that sub-figures are only supported in LaTeX output.
## Write raw content (\*) {#raw-content}
The technique introduced in Section \@ref(raw-latex) is actually a general technique. You can protect any complex raw content in Markdown by specifying the content as "raw." For example, if you want to write raw HTML content, you can use the attribute `=html`:
````md
```{=html}
<p>Any <strong>raw</strong> HTML content works here.
For example, here is a Youtube video:</p>
<iframe width="100%" height="400"
src="https://www.youtube.com/embed/s3JldKoA0zw?rel=0"
frameborder="0" allow="autoplay; encrypted-media"
allowfullscreen></iframe>
```
````
The attribute name is the Pandoc output format name. If you want to know the output format name, you may check the output of the code chunk below inside an Rmd document\index{knitr!pandoc\_toc()}:
````md
```{r}`r ''`
knitr::pandoc_to()
```
````
Please note that raw content is only visible to a specific output format. For example, raw LaTeX content will be ignored when the output format is HTML.
## Custom blocks (\*) {#custom-blocks}
<!-- https://stackoverflow.com/questions/36293511/creating-custom-blocks-in-rstudios-bookdown -->
[Section 2.7](https://bookdown.org/yihui/bookdown/custom-blocks.html) of the **bookdown** book mentioned how we can use custom blocks in R Markdown to customize the appearance of blocks of content. This can be a useful way to make some content stand out from your report or book, to make sure that your readers take away the key points from your work. Examples of how these blocks could be used include:
- display a warning message to make sure users are using up-to-date packages before running your analysis;
- add a link at the beginning of your document to your GitHub repository containing the source;
- highlight key results and findings from your analysis.
In this section, we will explain how to create your own custom blocks for both PDF and HTML output. They can both use the same formatting syntax in the R Markdown document, but require different configurations.
### Syntax {#block-syntax}
The syntax for custom blocks is based on Pandoc's [fenced `Div` blocks.](https://pandoc.org/MANUAL.html#divs-and-spans) `Div` blocks\index{Div} are very powerful, but there is a problem at the moment: they mainly work for HTML output and do not work for LaTeX output.
Since version 1.16 of the **rmarkdown** package, it has been possible to convert `Div` blocks to both HTML and LaTeX. For HTML output, all attributes of the block will become attributes of the `<div>` tag. For example, a `Div` can have an ID (after `#`), one or multiple classes (class names are written after `.`), and other attributes. The following `Div` block
```md
::: {#hello .greeting .message style="color: red;"}
Hello **world**!
:::
```
will be converted to the HTML code below:
```html
<div id="hello" class="greeting message" style="color: red;">
Hello <strong>world</strong>!
</div>
```
For LaTeX output, the first class name will be used as the LaTeX environment name. You should also provide an attribute named `data-latex`\index{Div!LaTeX compatability} in the `Div` block, which will be the arguments of the environment. This attribute can be an empty string if the environment does not need arguments. We show two simple examples below. The first example uses the `verbatim` environment in LaTeX, which does not have any arguments:
````md
::: {.verbatim data-latex=""}
We show some _verbatim_ text here.
:::
````
Its LaTeX output will be:
```tex
\begin{verbatim}
We show some \emph{verbatim} text here.
\end{verbatim}
```
When the block is converted to HTML, the HTML code will be:
```html
<div class="verbatim">
We show some <em>verbatim</em> text here.
</div>
```
The second example uses the `center` and `minipage` environments to display some text in a centered box of half of the page width.
```md
:::: {.center data-latex=""}
::: {.minipage data-latex="{.5\linewidth}"}
This paragraph will be centered on the page, and
its width is 50% of the width of its parent element.
:::
::::
```
Note that we nested the `minipage` block in the `center` block. You need more colons for a parent block to include a child block. In the above example, we used four colons (you can use five or more) for the `center` block. The two blocks will be converted to the LaTeX code below:
```tex
\begin{center}
\begin{minipage}{.5\linewidth}
This paragraph will be centered on the page, and
its width is 50\% of the width of its parent element.
\end{minipage}
\end{center}
```
It is up to the user to define the appearance of their `<div>` blocks via CSS for the HTML output. Similarly, for LaTeX output, you may use the command `\newenvironment` to define the environment if it has not been defined, or `\renewenvironment` to redefine an existing environment in LaTeX. In the LaTeX definitions, you can decide on the appearance of these blocks in PDF. These customizations will normally be contained in their own files such as `style.css` or `preamble.tex`, and then included within the YAML options:
```yaml
---
output:
html_document:
css: style.css
pdf_document:
includes:
in_header: preamble.tex
---
```
Next we will demonstrate a few more advanced custom blocks that use custom CSS rules and LaTeX environments. You may find an additional example in Section \@ref(multi-column), in which we arranged multiple blocks in a multi-column layout.
### Adding a shaded box {#block-shaded}
First, we show how to include content in a shaded box. The box has a black background with an orange frame with rounded corners. The text in the box is in white.
For HTML output, we define these rules in a CSS file. If you are unfamiliar with CSS\index{CSS}, there are plenty of free online tutorials, e.g., https://www.w3schools.com/css/.
```{cat, class.source='css', engine.opts=list(file = 'css/box.css')}
.blackbox {
padding: 1em;
background: black;
color: white;
border: 2px solid orange;
border-radius: 10px;
}
.center {
text-align: center;
}
```
For LaTeX output, we create a new environment named `blackbox` and based on the LaTeX package **framed**\index{LaTeX package!framed}, with a black background and white text:
```{cat, class.source='latex', engine.opts=list(file = 'latex/blackbox.tex')}
\usepackage{color}
\usepackage{framed}
\setlength{\fboxsep}{.8em}
\newenvironment{blackbox}{
\definecolor{shadecolor}{rgb}{0, 0, 0} % black
\color{white}
\begin{shaded}}
{\end{shaded}}
```
We used the **framed** package in this book because it is fairly lightweight, but it is not possible to draw a colored frame with rounded corners with this package. To achieve the latter, you will need more sophisticated LaTeX packages such as **tcolorbox** (<https://ctan.org/pkg/tcolorbox>)\index{LaTeX package!tcolorbox}, which offers a set of very flexible options for creating shaded boxes. You can find many examples in its documentation. The LaTeX environment below will create a shaded box of similar appearance to the above CSS example:
```tex
\usepackage{tcolorbox}
\newtcolorbox{blackbox}{
colback=black,
colframe=orange,
coltext=white,
boxsep=5pt,
arc=4pt}
```
Now we can use our custom box in both PDF and HTML output formats. The source code of the box is:
```md
:::: {.blackbox data-latex=""}
::: {.center data-latex=""}
**NOTICE!**
:::
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
::::
```
The output is:
:::: {.blackbox data-latex=""}
::: {.center data-latex=""}
**NOTICE!**
:::
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
::::
### Including icons {#block-image}
We can make custom blocks even more visually appealing by including images in them. Images can also be an effective way to convey the content of the block. For the following example, we assume that we are working within a directory structure below, which is a simplified version of what is used to build this book:
```text
directory/
├── your-report.Rmd
├── style.css
├── preamble.tex
└── images/
└── ├── important.png
├── note.png
└── caution.png
```
We show the source code and output of the example before we explain how everything works:
```md
::: {.infobox .caution data-latex="{caution}"}
**NOTICE!**
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
:::
```
The output is:
::: {.infobox .caution data-latex="{caution}"}
**NOTICE!**
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
:::
For the HTML output, we can add an image to the box through the `background-image` property in CSS\index{CSS property!background-image}. We insert the image into the background, and add enough padding on the left-hand side to avoid the text overlapping with this image. If you are using local images, the file path to the images is provided relative to the CSS file. For example:
```css
.infobox {
padding: 1em 1em 1em 4em;
margin-bottom: 10px;
border: 2px solid orange;
border-radius: 10px;
background: #f5f5f5 5px center/3em no-repeat;
}
.caution {
background-image: url("images/caution.png");
}
```
Note that we used two class names, `.infobox` and `.caution`, on the outer block. The `infobox` class will be used to define the shaded box with a colored border, and the `caution` class will be used to include the image. The advantage of using two classes is that we can define more blocks with different icons without repeating the setup of the shaded box. For example, if we need a `warning` box, we only need to define the following CSS rule without repeating rules in `.infobox`:
```css
.warning {
background-image: url("images/warning.png");
}
```
Then you can create a `warning` box with the Markdown source code below:
```md
:::: {.infobox .warning data-latex="warning"}
Include the actual content here.
::::
```
For the PDF output, we can create an `infobox` environment based on the `blackbox` environment defined in the previous example, and add the icon to the left side of the box. There are multiple ways of including images in a LaTeX environment. Here is only one of them (it does not precisely reproduce the box style defined in the CSS above):
```{cat, class.source='tex', engine.opts=list(file = 'latex/infobox.tex')}
\newenvironment{infobox}[1]
{
\begin{itemize}
\renewcommand{\labelitemi}{
\raisebox{-.7\height}[0pt][0pt]{
{\setkeys{Gin}{width=3em,keepaspectratio}
\includegraphics{images/#1}}
}
}
\setlength{\fboxsep}{1em}
\begin{blackbox}
\item
}
{
\end{blackbox}
\end{itemize}
}
```
Below we show more example blocks with different icons:
::: {.infobox .warning data-latex="{warning}"}
**NOTICE!**
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
:::
::: {.infobox .note data-latex="{note}"}
**NOTICE!**
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
:::
::: {.infobox .important data-latex="{important}"}
**NOTICE!**
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
:::
::: {.infobox .tip data-latex="{tip}"}
**NOTICE!**
Thank you for noticing this **new notice**! Your noticing it has
been noted, and _will be reported to the authorities_!
:::
Alternatively, you may use the LaTeX package [**awesomebox**](https://ctan.org/pkg/awesomebox)\index{LaTeX package!awesomebox} to generate boxes with icons in the PDF output. This package gives you a much larger number of icons to choose from. We give a brief example below: please refer to the package documentation for the possible LaTeX environments and their arguments.
`r import_example('awesomebox.Rmd')`