forked from cosname/rmarkdown-guide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
03-document.Rmd
2408 lines (1665 loc) · 89.3 KB
/
03-document.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
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# (PART) 基于 R Markdown 的应用 {.unnumbered}
```{r echo = FALSE}
source("utils.R")
```
# 使用 R Markdown 创建常用文档 {#rmarkdown-document}
第 \@ref(rmarkdown-compile) 节介绍了 R Markdown 从源文档到输出的两步过程,分别是
1. R Markdown --> Markdown,由 **knitr** [@R-knitr] 完成;
2. Markdown --> 不同格式文档,由 Pandoc 完成。
Markdown 在发明之初的主要目的就是简化 HTML 内容的书写方式。例如要创建一个列表项,用 HTML 来写是
```html
<ul>
<li>列表项</li>
</ul>
```
而用 Markdown 来写则只需要
```markdown
- 列表项
```
又如要表示一段引用,用 HTML 来写是 `<blockquote>text</blockquote>`,用 Markdown 来写则只需要 `> text`。
Pandoc 大大扩展了 Markdown 的语法。更重要的是,Pandoc 使得将 Markdown 文档转换为多种输出格式成为可能。尽管这些文档大体可以按照背后的实现方式,分为 HTML、PDF 和 Microsoft Office 等三大类型,但是根据应用场景的差异,会有多种多样的具体样式。
鉴于每种样式通常会通过不同的 R Markdown 扩展软件包来实现,所以其设置和使用方面会有自身的特点。因此,接下来的一部分内容将依次介绍常用文档格式的使用方法。而本章则主要介绍将 R Markdown 源文件输出为各种常用文档格式的功能。
## HTML 文档 {#rmarkdown-html}
HTML 即超文本标记语言(Hyper Text Markup Language),该技术是互联网最重要的基础设施之一,是网上精彩纷呈内容的主要依托。HTML 文档不仅能够展示文字、图片、表格、公式等常规页面元素,而且还可以呈现音乐、视频、交互动画等丰富多样的多媒体内容。而同样的任务则是其它常见的文档格式如 PDF、Microsoft Word 等所不能完成的。因为 Markdown 技术在设计之初的输出格式就是 HTML,所以 HTML 文档不仅仅是最常用 R Markdown 输出格式,同时也拥有最丰富的功能,因此是在学习 R Markdown 技术的过程中首先需要了解这一部分内容。
严格意义上说,采用 R Markdown 和 HTML 技术呈现的网站、幻灯片等也都属于 HTML 格式的文档,不过这些形式的内容通常包含了多个 `.html` 格式的文件,而这里介绍如何通过 R Markdown 源文件生成一份**独立**的 `.html` 格式的文件。
前面提过,R Markdown 生成 HTML 文档的过程有一个中间步骤,就是 Markdown + HTML 模板。HTML 模板包括预定义的文档结构、 CSS 样式表和 JavaScript 动态网页功能等,所以最终渲染得到的 HTML 文档的一些功能可能依赖于特定 HTML 模板才能实现。对于一般用户而言,不了解这方面的知识并不影响正常使用 R Markdown 创建 HTML 文档。但是如果用户对此有所了解,那将有利于了解 HTML 文档的实现途径。
默认情况下,R Markdown 的 HTML 文档使用 `rmarkdown::html_document` 模板。除此之外, **rmarkdown** 之外的其它软件包也提供了各种不同类型的 HTML 模板文件(如 `bookdown::html_document2`,`pagedown::html_paged` 等)。因此,在这一部分将首先从 R Markdown 到 `html_document` 文档开始。
要创建一个 `html_document`,只需要在 R Markdown 的开头加入 YAML 格式的元数据。
``` {.yaml}
---
title: "文档标题"
author: "作者"
date: "创建时间"
output: html_document
---
```
在元数据中,还可以加入各种各样设置,从而改变文档的格式。例如下面的设置将为文档添加一个自动目录。
``` {.yaml}
---
title: "文档标题"
author: "作者"
date: "创建时间"
output:
html_document:
toc: true
---
```
### 目录和标题 {#html-title}
R Markdown 文件中使用的目录都是自动目录,是根据文档的层次结构(一级标题、二级标题等)自动生成的。这一部分介绍如何在 HTML 文档中设置自动目录。
#### 显示目录 {#html-toc}
在开头的元数据中,使用 `toc: true` 可以打开文档的目录。目录会从 HTML 的标题自动生成,目录的层级由 `toc_depth` 的值确定(默认为 3)。例如:
``` {.yaml}
---
title: "标题"
output:
html_document:
toc: true
toc_depth: 2
---
```
在上面的例子中,目录中将包含 HTML 文档中的一级标题和二级标题。
#### 悬停目录 {#html-toc-float}
当把 `toc_float` 设为 `true` 的时候,目录会在侧边栏悬停。这样就可以随时借助目录在一篇比较长的文档中跳转了。
``` {.yaml}
---
title: "标题"
output:
html_document:
toc: true
toc_float: true
---
```
通过改变 `toc_float` 的选项,可以控制侧边栏的折叠和动画。其中:
- `collapsed` (默认为 `true`)控制文档第一次打开时目录是否被折叠。如果为 `true` 则只显示高级别的标题(二级标题及以上元素);
- `smooth_scroll` (默认为 `true`)控制页面滚动时,标题是否会随之变化。
``` {.yaml}
---
title: "标题"
output:
html_document:
toc: true
toc_float:
collapsed: false
smooth_scroll: false
---
```
#### 显示标题编号 {#html-number-sections}
使用 `number_sections` 可以在标题开头加上编号。一级标题编号为 "1 一级标题",二级标题为"1.1 二级标题"。
``` {.yaml}
---
title: "标题"
output:
html_document:
toc: true
number_sections: true
---
```
#### 使用标签页展示小标题的内容 {#html-tabset}
在 HTML 文档中使用标签页非常简单,只需要在标题后附加 `{.tabset}` 标签即可。
``` {.markdown}
## 季度报表(应用 `.tabset` 标签) {.tabset}
### 按产品汇总
(具体的报表内容)
### 按区域汇总
(具体的报表内容)
```
在此基础上,添加相关的额外标签还可以控制标签的样式和行为。其中:
- `.tabset-fade` 将为标签切换过程加入淡入淡出的动画效果;
- `.tabset-pills` 将为标签文字加上预设的 `.tabset-pills` 样式(图 \@ref(fig:html-tabset))。
```{r html-tabset, fig.cap="标签的默认样式及 `.tabset-pills` 样式", echo = FALSE, out.width="70%", fig.align="center"}
knitr::include_graphics("examples/tabset-example.png", dpi = NA)
```
### 主题和样式 {#html-theme}
#### 可选的文档主题样式 {#html-theme-list}
```{r echo=FALSE}
theme_link <- function(name = "", base_url = "https://bootswatch.com/3/") {
glue::glue("[{name}]({base_url}{name})",
name = name,
base_url = base_url
)
}
```
为了满足颜值党的差异化需求,`html_document` 自带了多个不同的主题。这些主题来自于 [Bootswatch](https://bootswatch.com/3/)\index{Bootswatch}。可用的主题名称包括 `r theme_link("default")`,`r theme_link("cerulean")`,`r theme_link("journal")`,`r theme_link("flatly")`,`r theme_link("darkly")`,`r theme_link("readable")`,`r theme_link("spacelab")`,`r theme_link("united")`,`r theme_link("cosmo")`,`r theme_link("lumen")`,`r theme_link("paper")`,`r theme_link("sandstone")`,`r theme_link("simplex")` 和 `r theme_link("yeti")` 等等。
主题使用 `theme` 参数设置:
``` {.yaml}
---
title: "标题"
output:
html_document:
theme: darkly
---
```
应用 `r theme_link("darkly")`主题样式的效果如图 \@ref(fig:first-rmd-theme-darkly) 所示,感兴趣的读者可以自行尝试其它样式。
```{r first-rmd-theme-darkly, fig.cap="应用 darkly 主题后的文档样式。", echo = FALSE}
knitr::include_graphics("examples/first-rmd-theme-darkly.png", dpi = NA)
```
如果设置为 `theme: null`,那么将不会应用任何主题,此时可以通过指定自定义的 CSS 样式表来进行格式化。
``` {.yaml}
---
title: "标题"
output:
html_document:
theme: null
css: style.css
---
```
#### 可选的代码高亮样式 {#html-code-highlight}
代码高亮也有可选的多种样式,包括 `default`,`tango`,`pygments`,`kate`,`monchrome`,`espresso`,`zenburn`,`haddock`,`breezedark` 和 `textmate` 等。
在元数据中,使用 `highlight` 参数指定代码高亮样式。下面的示例中将代码高亮设为 `tango`,更多的代码高亮样式见图 \@ref(fig:html-code-highlight-example)。
``` {.yaml}
---
title: "标题"
output:
html_document:
highlight: tango
---
```
(ref:figcap-html-code-highlight-example) 可选的代码高亮样式
```{r html-code-highlight-example, fig.cap="(ref:figcap-html-code-highlight-example)", fig.show="hold", out.width="70%", echo=FALSE}
code_highlight_examples <- list.files("examples/", "code-highlight-example.*\\.png", full.names = TRUE)
knitr::include_graphics(path = code_highlight_examples, dpi = NA)
```
跟上面的 `theme` 属性一样,`highlight` 也可以设为 `null`,这样的话代码将不显示高亮。
#### 自定义样式表 {#html-style-css}
不论有没有应用主题和代码高亮,用户都可以使用 `css` 参数指定附加样式表。附加样式表中的定义优先级更高,当被应用到特定元素上去之后,可以改变元素的外观。
``` {.yaml}
---
title: "标题"
output:
html_document:
theme: null
highlight: null
css: styles.css
---
```
如果在 `styley.css` 中定义了两个名为 `#nextsteps` 和 `.emphasized` 的新样式,分别用于指定 HTML 文档中 `id = "nextsteps"` 和 `class = "emphasized"` 这两种元素的外观。
``` {.css}
#nextsteps {
color: blue;
}
.emphasized {
font-size: 1.2em;
}
```
那么,就可以通过在行尾大括号中添加元素 id 和 CSS 类的方法,对某个二级标题(此处为“这里强调一下下一步”)应用这个样式:
``` {.markdown}
## 这里强调一下下一步 {#nextsteps .emphasized}
```
如果要应用多个 CSS 配置文件,可以这样写:
```yaml
output:
html_document:
css: ["style-1.css", "style-2.css"]
```
#### 通过 CSS 代码块定义样式 {#html-css-source}
除了像上面那样导入一个预定义的样式表,还可以直接在 R Markdown 中添加新的 CSS 定义。不过这种方法只适合针对个别元素进行个性化设置,如果 CSS 代码有很多行,或者想要在其它 R Markdown 文件中中交叉使用同样的定义,那么将其放在自定义样式表文件中会更加合适(参见 \@ref(html-style-css))。
`r import_example("chunk-custom.Rmd")`
```{r chunk-border, echo = FALSE, out.width="70%", fig.align="center", fig.cap = "一个具有浅红色背景和深红色边框的代码块"}
# import_example_result("chunk-custom.Rmd", vheight = 300)
knitr::include_graphics("examples/chunk-custom.png", dpi = NA)
```
#### 使用丰富多样的内置 CSS 样式 {#html-css-list}
大多数时候,用户并不需要自己定义 CSS 样式,因为 HTML 内置的主题中已经包含了丰富且高级的内置样式。
默认情况下,R Markdown 输出的 HTML 文档中,已经内嵌了 Bootstrap 框架\index{Bootstrap}[^about-bootstrap],因此可以使用一系列预定义的 CSS 样式。其中,可用的背景样式就包括 `"bg-primary"`,`"bg-success"`,`"bg-info"`,`"bg-warning"` 和 `"bg-danger"` 等。
[^about-bootstrap]: Bootstrap是一组用于网站和网络应用程序开发的开源前端框架,包括 HTML、CSS 及 JavaScript 的框架,提供字体排印、窗体、按钮、导航及其他各种组件及 Javascript 扩展,旨在使动态网页和 Web 应用的开发更加容易。
只需要在代码块属性中使用 `class.source` 标签,就可以应用这些预定义的 CSS 样式。
`r import_example("chunk-style.Rmd")`
以上生成的 HTML 输出如图 \@ref(fig:chunk-style-example) 所示。
```{r chunk-style-example, echo = FALSE, fig.cap="在代码块上应用内置 CSS 样式", out.width="70%", fig.align="center"}
# import_example_result("chunk-style.Rmd", vheight = 400, vwidth = 600)
knitr::include_graphics("examples/chunk-style.png", dpi = NA)
```
#### 代码折叠 {#html-code-folding}
当 **Knitr** 的代码块参数 `echo = TRUE` 时,R 代码将会输出到最终生成的文档中。
如果不需要显示源代码,可以直接设为 `echo = FALSE`。
如果既想要保留代码但又让其默认不显示,
则可以通过 `code_folding: hide` 参数来实现。
````{verbatim}
---
title: "代码折叠"
output:
html_document:
code_folding: hide
---
````
`code_folding: hide` 将折叠所有的代码块,用户可以通过点击来查看折叠的代码。如果想让部分代码块在一开始就显示,则可以在代码块选项中使用 `class.source = 'fold-show'`(图 \@ref(fig:fold-show))。
`r import_example("fold-show.Rmd")`
(ref:figcap-fold-show) 代码块的折叠和显示。图中每个代码区块旁边都有一个按钮,可以控制相应代码区块的显示方式;文档的右上角也有一个按钮,可以控制文档中全部代码区块的显示方式。
```{r fold-show, fig.cap="(ref:figcap-fold-show)",out.width="70%",fig.align="center", echo=FALSE}
# import_example_result("fold-show.Rmd", vwidth = 800)
knitr::include_graphics("examples/fold-show.png", dpi = NA)
```
这种操作也可以反向进行,即默认显示全部的代码区块,然后再将部分代码区块设为折叠。如下配置即可:
````{verbatim}
---
output:
html_document:
code_folding: show
---
```{r}
1 # 代码默认是显示的
```
```{r class.source = 'fold-hide'}
2 # 这一块代码将被折叠
```
````
如图 \@ref(fig:fold-show) 所示,在页面和每一个代码块的右上方有一个按钮。页面右上方的按钮可以控制全部代码块的显示和隐藏,代码块右上方的按钮则可以控制对应代码块的显示和隐藏。
#### 设置代码块内容可滚动 {#html-code-scroll}
如果想限制代码块的高度,特别是代码执行过程中输出内容的高度,还可以从相应内容的 CSS 样式上着手,即通过 `class.output` 和 `class.source` 来定义内容的高度。
下面是一个限制设定代码区块高度后,再通过滚动查看完整内容的例子:
`r import_example("html-scroll.Rmd")`
因为代码块是位于 `<pre class="sourcecode">` 标签内的,所以 `pre[class]` 操作符将限制代码块的高度为不超过 100 像素。 而将 `class.output ` 设为 `scroll-100` 则限制输出部分的高度为不超过 100 像素。最终效果如图 \@ref(fig:html-scroll-example) 所示。
```{r html-scroll-example, out.width="70%", fig.align="center", fig.cap="可以滚动的代码块", echo=FALSE}
# import_example_result('html-scroll.Rmd', vheight = 600, vwidth = 800)
knitr::include_graphics("examples/html-scroll.png", dpi = NA)
```
### 图片和数据框 {#html-pic}
#### 设置图片的属性 {#html-pic-setting}
下列参数可以调整生成的 HTML 文档中图片的属性:
- `fig_width`,`fig_height` 指定图片显示时的宽和高(默认为 7 × 5,单位英寸);
- `fig_retina` 开启视网膜屏幕优化(默认为 2,设为 `null` 时关闭优化);
- `fig_caption` 控制是否渲染图注;
- `dev` 设置图片输出设备,默认为 `png`。可以设置多个图片输出设备。
``` {.yaml}
---
title: "标题"
output:
html_document:
fig_width: 7
fig_height: 6
fig_caption: true
dev: c("png","pdf")
---
```
在代码框属性中,仍然可以通过 `fig.height`,`fig.width`,`fig.asp` 等参数来指定生成图片的高度、宽度和宽高比。
#### 插入外源图片 {#html-include-graphics}
虽然在 R Markdown 中可以使用 Markdown 语法和 HTML 语法插入图片,但是推荐使用 `knitr::include_graphics()` 的方式来完成这一操作。例如:
````{verbatim}
```{r}
knitr::include_graphics("https://r-project.org/Rlogo.png")
```
````
使用这种方法插入外源图片,可以方便地添加图注(使用 `fig.cap` 参数),以及设置图片的宽高等属性(图 \@ref(fig:include-graphics-example))。
```{r, include-graphics-example, echo = FALSE, fig.cap="插入外源图片的推荐方式", out.height = "30%"}
knitr::include_graphics("images/Rlogo.png", dpi = NA)
```
#### 输出数据框 {#html-df-print}
数据框是常见的数据结构,通过设置 `df_print` 参数,可以调整数据框的输出格式。可用的参数如表 \@ref(tab:df-print) 所示。
```{r, df-print, echo=FALSE}
knitr::kable(
data.frame(
取值 = c("default", "kable", "tibble", "paged"),
说明 = c("使用 print.data.frame 函数", "使用 knitr::kable 函数", "使用 tibble::print.tbl_df 函数", "使用 rmarkdown::paged_table 来创建一个分页的表格")
),
caption = "参数及其对应的含义"
)
```
```{r echo=FALSE, out.height = "40%"}
# @TODO: 截图修改完善
template <- xfun::magic_path("df-print-example.Rmd")
outfile <- xfun::with_ext(template, ".html")
snapshots <- lapply(c("default", "kable", "tibble", "paged"), function(x) {
rmarkdown::render(template,
rmarkdown::html_document(df_print = x),
params = list(subtitle = x),
envir = new.env(),
quiet = TRUE
)
html_screenshot(outfile, outfile = xfun::with_ext(template, paste0(x, ".png")))
})
unlink(outfile)
knitr::include_graphics(unlist(snapshots), dpi = NA)
```
除了几种预定义的样式外,`df_print` 还可以接受一个自定义函数精确控制打印表格的细节。例如,`kable` 样式也可以通过自定义函数定义:
````{verbatim}
---
output:
html_document:
# 等同于 df_print: kable
df_print: !expr print.me <- function(x, ...) { knitr::knit_print(knitr::kable(x, ...))}
---
````
`!expr` 可以在 YAML 元数据插入代码,详情可见文档 `?yaml::yaml.load()` 。自定义函数 `print.me()` 将被用于打印数据框输出。
如果数据框的打印函数较为复杂,不适于插入 YAML,另外一种办法是覆盖 `knitr::knit_print()` 函数在 `data.frame` 对象上的方法,如下所示:
`r import_example("examples/df-print-function.Rmd")`
```{r, echo = FALSE, fig.cap = "用自定义函数控制数据框的打印格式", out.width = "90%"}
import_example_result("examples/df-print-function.Rmd")
```
#### 分页打印数据框时的附加参数 {#html-df-print-paged}
若把 `df_print` 参数设为 `paged`,数据框将支持行列的分页,效果如图 \@ref(fig:paged) 所示。
````{verbatim}
---
title: "发动机测试和汽车道路测试"
output:
html_document:
df_print: paged
---
```{r}
mtcars
```
````
```{r paged, echo=FALSE, fig.cap='HTML文档中分页显示的数据框', out.width='100%'}
knitr::include_graphics("images/paged.png", dpi = NA)
```
表 \@ref(tab:paged-additional) 列出了这种情况下可以使用的附加参数。
```{r paged-additional, echo=FALSE}
knitr::kable(
data.frame(
参数名 = c("max.print", "rows.print", "cols.print", "cols.min.print", "pages.print", "paged.print", "rownames.print"),
说明 = c("显示的总行数", "一页显示的行数", "一页显示的列数", "最少显示几列", "下方显示页面导航链接的数目", "设为 FALSE 则不输出分页的表格", "设为 FALSE 时不显示行的名称 ")
),
caption = "分页 HTML 表格的附加可用参数"
)
```
这些参数可以在代码块中使用。
````{verbatim}
```{r cols.print=3, rows.print=3}
mtcars
```
````
### 组件和内容 {#html-module}
#### 理解 HTML 文档的依赖关系 {#html-dependency}
R Markdown 输出 HTML 文档时依赖于软件包提供的 HTML 模板。
实际上,HTML 文档的样式和功能很大程度上依赖于一些 CSS 样式和 JavaScript 库的支持。
这里面包括 [Bootstrap](https://getbootstrap.com/)[^about-bootstrap],[JQuery](https://jquery.com/) 等优秀的开源项目。前者是一个通用的网站开发框架,后者是一个通用的 JavaScript 库。
默认情况下,R Markdown 输出的 HTML 文档是一个单一的 `.html` 文件。这是由 `self_contained: true` 控制的。`.html` 文件中,会使用 `data:` 存储包括 JavaScript、CSS、图片和视频在内的全部资料。这样的一个封装,使得用户可以像分享 PDF 或 Word 文档那样分享文件,同时享受超链接、动态效果等一系列 HTML 特性。
如果指定 `self_contained: false`,那么 HTML 文档将会将自身的依赖文件单独存放。
```yaml
---
title: "标题"
output:
html_document:
self_contained: false
---
```
默认情况下,在 `.html` 文件同一目录会生成同名的 `_files` 文件夹,存放相应的依赖文件。下面是默认情况下一份 HTML 文档所包含的依赖文件。
```
+---anchor-sections-1.0
+---bootstrap-3.3.5
| +---css
| | \---fonts
| +---fonts
| +---js
| \---shim
+---header-attrs-2.5
+---highlightjs-9.12.0
+---jquery-1.11.3
\---navigation-1.1
```
存放这些依赖文件的文件夹位置可以由 `lib_dir: xxx` 指定,例如:
```yaml
---
title: "标题"
output:
html_document:
self_contained: false
lib_dir: libs
---
```
依赖文件的内容会随配置变化,例如当在 YAML 配置中加入 `df_print: paged` 之后,依赖文件中会增添一个`pagedtable-1.1` 子文件夹。
依赖文件夹按照 **库名** + **版本号** 的规则命名。R Markdown 会自动负责引用和维护这些依赖文件,因此绝大部分情况下用户不需要关心依赖文件的具体内容。
当单个文档体积较小,同时又有多个类似的文档的时候,如果每个文档都生成自己的那一份依赖文件就会浪费磁盘空间。这种情况下,将库文件统一存储在指定的 `libs` 文件夹,可以实现库文件公用。
对于一些体积较大的依赖库,R Markdown 不会将其下载到用户的电脑上,而是通过远程 CDN 链接引入。例如第 \@ref(#html-mathjax) 中的 MathJax 库。
#### MathJax 库的配置 {#html-mathjax}
HTML 文档需要 [MathJax](https://www.mathjax.org)\index{MathJax} 脚本来渲染 Latex 和 MathML 公式[^about-mathml],调用 [MathJax](https://www.mathjax.org) 的方式则可以通过 `mathjax` 参数来调整。
[^about-mathml]: MathML,中文翻译为“数学标记语言”,是一种基于 XML 的标准,用来描述数学符号和公式。它的目标是把数学公式集成到互联网和其他文档中。从 2015 年开始,MathML 成为了 HTML5 的一部分和 ISO 标准。
- `"default"`:默认配置,会通过 HTTPS 链接从 RStudio 的 CDN 网络服务器上调用;
- `"local"`:与 `self_contained: false` 联合使用时,会将 MathJax 库文件保存在本地目录中;
- 还可以将 `mathjax` 的值设置成一个 URL 链接,指向可用的 MathJax 库文件地址;
- `null`:完全不使用 MathJax。
例如,使用 MathJax 的本地拷贝可以如下配置:
```yaml
---
title: "标题"
output:
html_document:
mathjax: local
self_contained: false
---
```
为 MathJax 配置一个新的可用来源。
```yaml
---
title: "标题"
output:
html_document:
mathjax: "http://example.com/MathJax.js"
---
```
不使用 MathJax。
```yaml
---
title: "标题"
output:
html_document:
mathjax: null
---
```
#### 是否保留 Markdown {#html-keep-md}
**knitr** 处理 R Markdown 文件时,会先生成一个 Markdown 文件(`*.md`),随后再由 Pandoc 转换成 HTML 文档。如果需要保留这个 Markdown 文件,可以使用 `keep_md` 选项。
```yaml
---
title: "标题"
output:
html_document:
keep_md: true
---
```
#### 使用自定义的 HTML 模板 {#html-template}
使用 `template` 选项,可以配置 Pandoc 转换时使用的模板。
```yaml
---
title: "标题"
output:
html_document:
template: another_template.html
---
```
Pandoc 模板遵循特定的格式,有关的进一步信息可以在 [Pandoc 模板](http://pandoc.org/MANUAL.html#templates) 页面获得。
下面是一个 HTML 模板的示例:
```html
<html>
<head>
<title>$title$</title>
$for(css)$
<link rel="stylesheet" href="$css$" type="text/css" />
$endfor$
</head>
<body>
$body$
</body>
</html>
```
这其中包括一些变量,如 `$title$`,`$body$` 等。这些变量由 Pandoc 定义,完整的变量列表可以参考 [Pandoc 的官方文档](https://pandoc.org/MANUAL.html#templates)\index{Pandoc template}。
这样的 HTML 模板使得高度定制化的输出成为可能。例如,可以在 `<head>` 区域加入任意的 CSS 样式, JavaScript 代码,以及其它的开源库。 另外,还可以定义一些新变量来控制文档的格式化。例如,定义一个布尔值 `draft` 来确定文档是一个草稿还是最终版本。
```html
<head>
<style type="text/css">
.logo {
float: right;
}
</style>
</head>
<body>
<div class="logo">
$if(draft)$
<!-- 使用 draft.png 以表明这是一份草稿 -->
<img src="images/draft.png" alt="您正在阅读的是一份草稿" />
$else$
<!-- 在最终版本中插入正式 LOGO -->
<img src="images/logo.png" alt="您正在阅读本文档的正式版本" />
$endif$
</div>
$body$
</body>
```
`draft` 变量可以通过 YAML 元数据来赋值。这样根据 `draft` 设定的不同值,R Markdown 可以编译出具有不同 LOGO 图像的 HTML 文档,从而可以直观的显示读者目前看到的这份文档是一个草案还是最终版本。
```yaml
---
title: "一份重要的报告"
draft: true
output:
html_document:
template: my-template.html
---
```
*说明*:**rmarkdown** 软件包默认使用自带的 HTML 模板,一些方面与 Pandoc 默认的模板存在差异。如果有 `template: null` 的话,则 Pandoc 的模板会被使用。
#### 包含其它文件 {#html-includes}
使用 `includes` 选项,可以在 HTML 文档的不同位置嵌入其它的 HTML 格式内容。可选的位置包括在 HTML 文档的 `header`、`body` 前/后等[^html-includes]。
[^html-includes]: 这样的用法在配置 **bookdown** 创作的图书时非常常见(参见 \@ref(rmarkdown-bookdown))。
```yaml
---
title: "标题"
output:
html_document:
includes:
in_header: header.html
before_body: doc_prefix.html
after_body: doc_suffix.html
---
```
这种方式可以很方便的为文档加入一些第三方功能和公用的元件。例如在 `in_header` 中导入预定义的 CSS 样式表和 Javascript 脚本,在 `before_body` 中加入导航栏,在 `after_body` 中加入一个底栏等。
下面的例子中,即添加了一个简单的底栏。将其中内容保存到一个 HTML 文件中,放在 `after_body` 后面即可。
```html
<div class="footer">Copyright © R Markdown 指南 2021</div>
```
除了以上几种常用的位置,还可以在任意地方插入 HTML 内容。实现这一功能的途径至少有两种。
一是使用 `htmltools::includeHTML()` 方法:
````{verbatim}
```{r, echo=FALSE, results='asis'}
htmltools::includeHTML("file.html")
```
````
二是使用 `xfun::file_string()` 方法:
````{verbatim}
```{r, echo=FALSE, results='asis'}
xfun::file_string("file.html")
```
````
需要注意的是,导入的 HTML 文件必须是 HTML 片段 (见第 \@ref(html-fragments) 节),而不能是一个完整的 HTML 文档。完整的 HTML 文件中有 `<html>` 标签,解析时会造成错误。比如下面就是一个无效的例子:
```html
<html>
<head></head>
<body>
父 HTML 文件。
<!-- htmltools::includeHTML() 将插入下列 HTML 代码 -->
<html>
<head></head>
<body>
子 HTML 文件。
</body>
</html>
<!-- 上面的内容即插入的 HTML 代码,插入后新文档的解析会出错 -->
</body>
</html>
```
#### 生成 HTML 片段 {#html-fragments}
HTML 片段是一个不完整的 HTML 文件,通过输出格式 `html_fragment` 控制。例如:
````{verbatim}
---
title: "输出一个 HTML 片段"
output: html_fragment
---
HTML 片段可以有标题和代码区域,但是不包含任何 CSS 定义。
```{r}
head(mtcars)
```
````
上面文档的编译输出是:
`r import_example("html-fragment.html")`
以上 HTML 片段导入本节后的内容是:
```{r echo=FALSE, results="asis"}
htmltools::includeHTML("examples/html-fragment.html")
```
*HTML 片段的内容到此结束*。
HTML 片段仅包括用于显示内容的最小代码,不包含 `<html>`, `<body>` 等标签,也不携与主题或代码高亮相关的依赖文件。这样的好处是可以将它们嵌入到其它人意 HTML 文档中,而不会造成标签冲突。嵌入对象不一定是 R Markdown 生成的,例如可以为博客网站嵌入一个 R Markdown 生成的图表片段,
#### 使用自定义的浏览器图标 {#html-favicon}
通过在 `in_header` 部位导入 HTML 内容,可以为 HTML 文档设定一个自定义的浏览器图标。
将下面的内容保存到一个名为 `header.html` 的文档中。
```html
<link rel="shortcut icon" href="{path to favicon file}" />
```
然后通过 `includes` 导入文件的内容,则可以改变浏览当前文档时的浏览器图标。
```yaml
output:
html_document:
includes:
in_header: header.html
```
#### 共用 YAML 配置文件 {#html-shared-yaml}
当前目录中的 `_output.yml` 文件是一个配置文件,其中的设置可以被目录下所有的 R Markdown 文档公用。需要注意的是,该文件中的内容会在编译时加载到 `output` 选项中,因此 `_output.yml` 不应该定义 `output` 选项,而应该直接设置 `output` 选项中的子选项。如下所示:
```yaml
html_document:
self_contained: false
theme: united
highlight: textmate
```
错误的做法是在 `_output.yml` 中定义 `output` 选项:
```yaml
---
# 错误:这里不需要 output
output:
html_document:
self_contained: false
theme: united
highlight: textmate
---
```
#### 允许下载源文件 {#html-code-download}
当分享一个 R Markdown 生成的 HTML 文档给他人的时候,对方可能还需要提供 `.Rmd` 源文件。在头文件中配置 `code_download` 参数可以在 HTML 文档中嵌入源文件。
```yaml
output:
html_document:
code_download: true
```
打开 `code_download` 选项后,页面中会出现一个下载按钮,点击下载按钮即可获得源文件。
#### 嵌入数据或其它文件 {#html-embed}
嵌入 `.Rmd` 源文件可能还不足以重现 R Markdown 中结果,通常还会需要原始数据等其它内容。要将这些内容嵌入 HTML 文档中,也是很容易实现的。
这一功能通过 **xfun** 软件包[@R-xfun] 实现,依赖于 `htmltools` 和 `mime` 软件包。要使用这一功能,首先确保这两个软件包可用。
```{r, eval=FALSE}
xfun::pkg_load2(c("htmltools", "mime"))
```
现在,就可以随意嵌入各种文件了。
`r import_example("embed-file.Rmd")`
不仅如此,还可以用正则表达式批量嵌入文件。
```{r eval=FALSE}
# 嵌入当前目录下所有的 Rmd 和 csv 文件
xfun::embed_files(list.files(".", "[.](Rmd|csv)$"))
```
当嵌入多个文件时,R Markdown 首先将这些文件压缩成 Zip 格式,然后将 Zip 文件嵌入到 HTML 文档中。
## PDF 文档 {#rmarkdown-pdf}
```{r include=FALSE}
# 考虑到中国受众的特点,本章尽可能回避了 LaTeX 代码的出现。
```
这一部分讲述将 R Markdown 输出为 PDF 的功能。PDF 是便携式文档格式(**P**ortable **D**ocument **F**ormat)的缩写,这是一种常见的文档格式,
特别是在文件、学术论文中广泛使用。它具有文件体积小、保真度高和安全的特点。
R Markdown 并不能直接输出 PDF 文档,而是会输出 LaTeX 文件,LaTeX 文件经过处理后生成 PDF。因此,使用 R Markdown 输出 PDF 文件时,可以充分发挥 LaTeX 的优势。在需要的时候,可以直接使用 LaTeX 代码编写内容,应用 LaTeX 的包和模板,添加标题、脚注、子图等。
不过,LaTeX 技术对于大多数人可能都还比较陌生,而在生成 PDF 文档的过程中,很多问题都跟 LaTeX 的配置有关。这几乎是不可避免的,因此在开始正式的内容前,需要确保已经安装了 **TinyTex** 以及一些依赖的 LaTeX 组件。具体的安装步骤和疑难解答请参见前文(\@ref(install-tinytex)),此处不再赘述。
### 从 R Markdown 到 PDF 文档 {#pdf-rmd}
要输出 PDF 文档,只需要在 R Markdown 开头的 YAML 配置中指定 `pdf_document` 即可。
``` yaml
---
output: pdf_document
---
```
只需要这样一个改动,就可以得到一份 PDF 文档。
### 在 PDF 文档中使用中文的注意事项 {#pdf-chinese}
如果这份 PDF 中仅含有英文,那么不需要做额外的设置。
但是对于中文用户而言,可能会出现错误。这是因为,PDF 所依赖的 LaTeX 系统对中文的支持与 HTML 不同,需要做一些合适的设置。包括导入中文语言支持的 LaTeX 模块 **ctex**,以及使用一个对 Unicode 支持更好的 **xelatex** 引擎。
下面就是一份中文 PDF 文档的示例。
```{r, echo=FALSE}
import_example("examples/PDF-document-in-chinese.Rmd")
```
将这份 R Markdown 编译后,将会生成一份 PDF 文档。
```{r, echo=FALSE, out.width = "90%"}
knitr::include_graphics("examples/PDF-document-in-chinese.png", dpi = NA)
```
### 与 HTML 文档相通的设置 {#pdf-general-setting}
下面的这些设置与前文介绍的 HTML 文档中相应配置的用法基本相同,参考第 \@ref(rmarkdown-html) 节。
#### 显示目录 {#pdf-toc}
使用 `toc` 在 PDF 文档中加入目录,`toc_depth` 控制目录的深度。这点与 HTML 文档的用法一致[^PDF-vs-HTML]。
[^PDF-vs-HTML]: 实际上很多配置的名称都保持一致,但是也有不少会跟文档格式有关。如果发现改变了某个配置却没有效果,可能会跟配置的适用范围有关。
``` yaml
---
title: "五一劳动节加班三倍工资"
author: "张三"
date: "2021年5月1日"
output:
pdf_document:
toc: true
toc_depth: 2
---
```
如果 `toc_depth` 没有指定,则默认索引到二级标题(在 HTML 文档中默认索引到三级标题)。
使用 `number_sections` 可以在标题前面加入编号。
``` yaml
---
title: "五一劳动节加班三倍工资"
author: "张三"
date: "2021年5月1日"
output:
pdf_document:
toc: true
toc_depth: 2
number_sections: true
---
```
#### 图片相关的配置 {#pdf-figure}
- `fig_width` 和 `fig_height` 用于控制图片默认的宽和高(默认为 6.5 x 4.5 英寸)。
- `fig_crop` 控制 `pdfcrop` 的效果,功能是去掉图片边缘的空白(默认为 `true`)。
`pdfcrop` 是一个 LaTeX 组件,默认并没有被 `tinytex` 安装。推荐用户运行 `tinytex::tlmgr_install("pdfcrop")` 来安装它。同时,`pdfcrop` 依赖于系统中的存在的 `ghostscript`,因此还需要安装 [`ghostscript`](https://www.ghostscript.com/) \index{GhostScript}才能正常使用 `pdfcrop`。
- `fig_caption` 控制是否为图片添加图注(默认为 `true`)。
- `dev` 控制用于渲染图片的图像设备(默认为 `pdf`)。
``` yaml
---
title: "五一劳动节加班三倍工资"
author: "张三"
date: "2021年5月1日"
output:
pdf_document:
fig_width: 7
fig_height: 6
fig_caption: true
---
```
#### 打印数据框 {#pdf-df-print}
通过 `df_print` 控制数据框打印的原理在 PDF 中与 HTML 相同,见表 \@ref(tab:df-print)。
#### 代码高亮 {#pdf-code-highlight}
与 HTML 文档相同,这里可用 `highlight` 参数配置代码高亮的样式(见第 \@ref(html-theme) 节)。例如:
``` yaml
---
title: "五一劳动节加班三倍工资"
author: "张三"
date: "2021年5月1日"
output:
pdf_document:
highlight: tango
---
```
### LaTeX 选项 {#pdf-latex}