-
Notifications
You must be signed in to change notification settings - Fork 0
/
visualization-tikz.qmd
512 lines (425 loc) · 21.7 KB
/
visualization-tikz.qmd
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
# TikZ 入门 {#sec-basic-tikz}
```{r}
#| echo: false
source("_common.R")
```
有一些示意图是用来表达数据探索的思路的,而不是直接探索数据的工具。比如象限图、甘特图、思维导图、网络图等,可以用 TikZ 绘制这类图形来阐述分析维度、思路、结构等。当然,绘制这类示意图不仅限于 TikZ,还有很多其它工具,如 LaTeX 社区的 PSTricks,JavaScripts 社区的 Mermaid,软件 Graphviz 等。
## standalone 宏包 {#sec-tikz-standalone}
最常见的 LaTeX 文档类有 article、report、beamer、book,分别对应文章、报告、演示和书籍。有的宏包在此基础上扩展功能,比如 ctex 宏包提供中文支持,有四个文档类 ctexart、 ctexrep 、ctexbeamer 和 ctexbook 与之对应起来。standalone 宏包提供 standalone 文类主要用于绘制独立的图片,默认情况下,文档四周多余的空白部分会被裁剪掉。在 LaTeX 环境中,推荐使用 TikZ 来绘图。standalone 文类可与 tikz 宏包一起使用,生成一张张由 TikZ 代码绘制的独立图片。下面举个简单的例子,用 TikZ 绘制两个坐标轴。
``` latex
\documentclass[tikz,border=1mm]{standalone}
\begin{document}
\begin{tikzpicture}
\draw[<->] (6,0) -- (0,0) node[left]{O} -- (0,6);
\end{tikzpicture}
\end{document}
```
standalone 文类启用 `tikz` 选项来绘图,选项 `border=1mm` 表示图片四周的边空保留 1 毫米,文档内容放在 document 环境里,TikZ 绘图代码放在 tikzpicture 环境中,命令 `\draw` 负责绘制具体的图形,用 XeLaTeX 编译,效果如 @fig-tikz 所示。
```{tikz}
#| label: fig-tikz
#| fig-cap: TikZ 绘图
#| engine-opts: !expr list(classoption="tikz,border=1mm")
#| fig-width: 3
#| fig-height: 3
#| echo: false
\begin{tikzpicture}
\draw[<->] (6,0) -- (0,0) node[left]{O} -- (0,6);
\end{tikzpicture}
```
standalone 文类有很多选项,下面介绍 4 个选项的常用内容。
- `class` 选项指定文类环境,默认值为 `article`,表示在 article 文类中绘图。其它选项还有 `beamer` ,表示在演示环境中绘图。在不同的文类中,图片渲染出来的效果不同。
- `tikz=true|false` 选项是否启用 TikZ 绘图,默认值是 `false` 。当显式地在 standalone 文类中启用 `tikz` 选项,就表示用 TikZ 绘图,将自动加载 tikz 宏包。与之类似的选项 `pstricks=true|false` ,表示是否启用 PSTricks 绘图,PSTricks 是LaTeX 社区中一套语法不同于 TikZ 的绘图工具。
- `crop=true|false` 选项是否裁剪变空,默认值是 `true` ,表示绘图区域以外的部分都裁剪掉。与之相关的另一个选项是 `border` ,可以更加精细地控制图片四周的各个边空。
- `border` 选项指定边空大小,默认值是 0,表示无边空。当 `crop=true` 时,再指定 `border` 选项,比如 `border=1mm` 表示图片四周的边空保留 1 毫米。图片四周的边空大小可以按照左、下、右、上的顺序指定,比如 `border={5mm 6mm 0mm -2mm}` 表示图片左边空 5 毫米、下边空 6 毫米、右边空 0 毫米、上边空负 2 毫米。
standalone 文类是支持 PSTricks 绘图的,下面在直角坐标系中绘制一个带阴影效果的圆,示例代码如下:
``` latex
\documentclass[pstricks,border={5mm 6mm 0mm -2mm}]{standalone}
\usepackage{pst-plot}
\begin{document}
\psset{xunit=0.15in, yunit=0.15in}
\begin{pspicture}(0,0)(11,11)
\psaxes[Dx=4,Dy=4, subticks=4]{->}(0,0)(0,0)(10,10)[$x$,0][$y$,0]
\pscircle[runit=0.15in, fillcolor=orange!50, fillstyle=solid,shadow=true](5,5){3}
\end{pspicture}
\end{document}
```
standalone 文类的选项 `pstricks` 表示启用 PSTricks 绘图环境,加载 pst-plot 宏包提供额外的命令,PSTricks 是基于 PostScript 语言的,每一个绘图命令都是 `\ps` 开头的,比如 `\psset` 、`\psaxes`、`\pscircle` 等。`\begin{pspicture}` 和 `\end{pspicture}` 之间是 PSTricks 绘图代码,`\begin{pspicture}` 之后的 `(0,0)(11,11)` 是左下和右上角两个坐标,定义了一个绘图区域。和 TikZ 绘图代码一样,也用 XeLaTeX 编译,效果如 @fig-pstricks 所示。
```{tikz}
#| label: fig-pstricks
#| fig-cap: PSTricks 绘图
#| engine-opts: !expr list(classoption="pstricks,border={5mm 6mm 0mm -2mm}",extra.preamble="\\usepackage{pst-plot}",template="code/tikz2pdf.tex")
#| fig-width: 3
#| fig-height: 3
#| echo: false
\psset{xunit=0.15in, yunit=0.15in}
\begin{pspicture}(0,0)(11,11)
\psaxes[Dx=4,Dy=4, subticks=4]{->}(0,0)(0,0)(10,10)[$x$,0][$y$,0]
\pscircle[runit=0.15in, fillcolor=orange!50, fillstyle=solid,shadow=true](5,5){3}
\end{pspicture}
```
可以在 Quarto 和 R Markdown 文档中插入 PSTricks 绘图代码,使用 **knitr** 包的 `tikz` 引擎绘图。只要修改模版文件 `tikz2pdf.tex` ,移除一行 `\usetikzlibrary{matrix}` ,不再加载 tikz 宏包及其 matrix 库。`TIKZ_CLASSOPTION` 不再仅限于 TikZ ,而是 standalone 文类的选项,相应地,`EXTRA_TIKZ_PREAMBLE_CODE` 变成一般的 LaTeX 文档的导言区,`TIKZ_CODE` 可以是 PSTricks 代码。新的模版文件 `tikz2pdf.tex` 如下:
``` latex
\documentclass[
%% TIKZ_CLASSOPTION %%
]{standalone}
%% EXTRA_TIKZ_PREAMBLE_CODE %%
\begin{document}
%% TIKZ_CODE %%
\end{document}
```
上 @fig-pstricks 即是由 **knitr** 包的 `tikz` 引擎渲染出来的。在代码块选项 `engine-opts` 中,传递一个列表,分别包含 `classoption`(standalone 文类选项)、 `extra.preamble`(导言区)、 `template` (TikZ 模版文件)三块内容。生成 @fig-pstricks 的 `engine-opts` 设置如下:
``` r
list(
classoption = "pstricks,border={5mm 6mm 0mm -2mm}",
extra.preamble = "\\usepackage{pst-plot}",
template = "code/tikz2pdf.tex"
)
```
其它选项和更多详细介绍见 standalone 宏包帮助文档。
## PGF 宏包 {#sec-tikz-pgf}
PGF 宏包提供一套易于学习和使用的绘图语法 TikZ,TikZ 是 TikZ ist kein Zeichenprogramm 的简写,命名有 Linux 哲学意味。下面比较详细的介绍 LaTeX 宏包 [PGF](https://ctan.org/pkg/pgf) 绘制曲线图的过程。
```{tikz}
#| label: fig-tikz-pgf1
#| engine-opts: !expr list(classoption="tikz,border=1mm")
#| fig-cap: PGF 绘制曲线图
#| fig-width: 3
#| fig-height: 3
\begin{tikzpicture}
\draw[<->] (6,0) -- (0,0) node[left]{O} -- (0,6);
\end{tikzpicture}
```
首先,`\draw` 命令绘制带箭头的坐标轴,坐标轴的范围 $[0,6]\times[0,6]$ 。坐标轴是由线构成的,线有虚线、实线,也有宽度和颜色,虚线还有不同类型,这些都是可以设置的参数,比如将 `\draw[<->]` 改为 `\draw[color=red,<->]` ,坐标轴颜色设置为红色。
```{tikz}
#| label: fig-tikz-pgf2
#| fig-cap: PGF 绘制曲线图
#| fig-width: 3
#| fig-height: 3
\begin{tikzpicture}
\draw[<->] (6,0) node[below]{$q$} -- (0,0) node[left]{O} -- (0,6) node[left]{$V(q)$};
\end{tikzpicture}
```
然后,在位置 (6,0) 和 (0,6) 分别添加节点 `node[below]{$q$}` 和 `node[left]{$V(q)$}` 。node 表示节点,节点的标签内容在大括号内,标签的位置在中括号内,这里,below 表示在位置 (6,0) 的下方。
```{tikz}
#| label: fig-tikz-pgf3
#| fig-cap: PGF 绘制曲线图
#| fig-width: 3
#| fig-height: 3
\begin{tikzpicture}
\draw[<->] (6,0) node[below]{$q$} -- (0,0) node[left]{O} -- (0,6) node[left]{$V(q)$};
\draw[very thick] (0,0) to [out=90,in=145] (5,4.5);
\end{tikzpicture}
```
最后,从点 (0,0) 至点 (5,4.5) 绘制一条非常粗的曲线。曲线从点 (0,0) 出去的时候,是以 90 度垂直水平轴的方向出去的,到点 (5,4.5) 是以 145 度方向进入的。角度是按照逆时针方向计算的。线的粗细、方向都是由参数决定的。
在这里,TikZ 是用来绘制示意图的,不需要知道每个命令的每个参数的取值有哪些。关键是知道自己想要画什么,其实,可以用铅笔在纸上以最快的方式绘制草图,了解每个绘图元素,然后查找 PGF 帮助手册,找到对应的命令和参数,将草图工整地誊抄一遍。
## 三维图 {#sec-tikz-pgfplots}
顾名思义,[pgfplots](https://ctan.org/pkg/pgfplots) 宏包基于 PGF 的,用它来绘制三维图形是非常方便的。
``` latex
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=7cm,compat=1.17}
\begin{document}
%% TikZ 代码%%
\end{document}
```
首先加载 pgfplots 宏包,设置全局的绘图参数,`width=7cm` 表示绘图页面宽度,`compat=1.17` 表示使用 pgfplots 的版本。
```{tikz}
#| label: fig-tikz-viridis
#| fig-cap: TikZ 绘制三维图 viridis 调色板
#| engine-opts: !expr list(extra.preamble=c("\\usepackage{pgfplots}","\\pgfplotsset{width=7cm,compat=1.17}"))
#| fig-width: 4
\begin{tikzpicture}
\begin{axis}[
hide axis,
colormap/viridis
]
\addplot3[
mesh,
samples=50,
domain=-8:8
]
{ sin(deg(sqrt(x^2+y^2)))/sqrt(x^2+y^2) };
\addlegendentry{$\frac{\sin(r)}{r}$}
\end{axis}
\end{tikzpicture}
```
```{tikz}
#| label: fig-tikz-jet
#| fig-cap: TikZ 绘制三维图 jet 调色板
#| engine-opts: !expr list(extra.preamble=c("\\usepackage{pgfplots}","\\pgfplotsset{width=7cm,compat=1.17}"))
#| fig-width: 4
\begin{tikzpicture}
\begin{axis}[
hide axis,
colormap/jet
]
\addplot3[
mesh,
samples=50,
domain=-8:8
]
{ sin(deg(sqrt(x^2+y^2)))/sqrt(x^2+y^2) };
\addlegendentry{$\frac{\sin(r)}{r}$}
\end{axis}
\end{tikzpicture}
```
```{tikz}
#| label: fig-tikz-cool
#| fig-cap: TikZ 绘制三维图 cool 调色板
#| engine-opts: !expr list(extra.preamble=c("\\usepackage{pgfplots}","\\pgfplotsset{width=7cm,compat=1.17}"))
#| fig-width: 5
\begin{tikzpicture}
\begin{axis}[
hide axis,
colormap/cool,
colorbar sampled,
domain=-8:8
]
\addplot3[
contour filled={
number=20,
},
]{sin(deg(sqrt(x^2+y^2)))/sqrt(x^2+y^2)};
\addlegendentry{$\frac{\sin(r)}{r}$}
\end{axis}
\end{tikzpicture}
```
- `\begin{axis}` 和 `\end{axis}` 环境有很多配置选项,参数值 `[hide axis, colormap/viridis]` 中 `hide axis` 表示隐藏坐标轴,`colormap/viridis` 表示三维图形的调色板采用 viridis 。`colormap` 支持很多不同的调色板,上面列举了两个。其实还可以增加不同的选项,比如添加选项 `colorbar sampled` 会生成一个颜色条,还可以添加选项 `colorbar horizontal` 来水平放置颜色条。
- 可以在导言区加载 `\usetikzlibrary{pgfplots.colorbrewer}` 导入 [ColorBrewer](https://colorbrewer2.org/) 系列调色板,方便后续绘图时调用。作用与 R 语言中的 **RColorBrewer** 包类似,调色板名称略有不同,前者 `PuBu-9` 对应后者 `PuBu` 。
- `\addplot3` 命令绘制函数 `sin(deg(sqrt(x^2+y^2)))/sqrt(x^2+y^2)` 的三维图像,即函数 $f(x,y)=\frac{\sin(\sqrt{x^2 + y^2})}{\sqrt{x^2 + y^2}}$ 的三维图像。参数值 `[mesh, samples=50, domain=-8:8]` 中 `mesh` 表示三维图形是网格状,其它可选值还有曲面图 `surf` 、填充等值线图 `contour filled` 等,`samples=50` 表示网格密度是 50,`domain=-8:8` 表示横纵坐标的范围都是 $[-8,8]$ 。
- `\addlegendentry` 添加图例,图例标签是 $\frac{\sin(r)}{r}$ ,颜色会随着调色板变化。
## 网络图 {#sec-tikz-network}
绘制网络图用 [tikz-network](https://ctan.org/pkg/tikz-network) 宏包,也是 PGF 的一个扩展包。图结构是根据顶点和边来定义的,图的复杂程度也可以用顶点和边的规模来衡量。图描述一种非线性的关系,有自己的一套语言,定义顶点 `\Vertex` 和边 `\Edge` 的两个命令是最基础的。下面绘制柯尼斯堡七桥问题对应的图。
``` latex
\documentclass[tikz]{standalone}
\usepackage{tikz-network}
\begin{document}
%% TikZ 代码%%
\end{document}
```
```{tikz}
#| label: fig-network-seven-bridges
#| fig-cap: 柯尼斯堡七桥
#| engine-opts: !expr list(extra.preamble=c("\\usepackage{tikz-network}"))
#| fig-width: 5
\begin{tikzpicture}
\Vertex[IdAsLabel, x=5, color=gray, size=1, fontsize=\large]{A}
\Vertex[IdAsLabel, x=10, color=gray, size=1, fontsize=\large]{B}
\Vertex[IdAsLabel, x=15, color=gray, size=1, fontsize=\large]{C}
\Vertex[IdAsLabel, x=10, y=6, color=gray, size=1, fontsize=\large]{D}
\Edge[label=2, bend=45, fontscale=2](A)(B)
\Edge[label=6, bend=30, fontscale=2](A)(D)
\Edge[label=3, bend=45, fontscale=2](B)(A)
\Edge[label=5, bend=45, fontscale=2](B)(C)
\Edge[label=4, bend=45, fontscale=2](C)(B)
\Edge[label=7, bend=30, fontscale=2](D)(C)
\Edge[label=1, fontscale=2](D)(B)
\end{tikzpicture}
```
- `\Vertex` 命令定义顶点(含标签),参数 `IdAsLabel` 表示顶点 ID 作为标签,参数 `x` 和 `y` 表示坐标位置,参数 `color` 表示顶点的填充色,参数 `size` 表示顶点的大小,参数 `fontsize` 表示标签文本的大小。
- `\Edge` 命令在已有顶点的基础上定义边,`(A)(B)` 表示从顶点 A 到顶点 B 有一条边,参数`label` 表示边上的标签文本,参数 `bend` 表示边的弧度,参数 `fontscale` 表示标签文本的大小。
不难看出,无论是顶点还是边,都有颜色、大小、标签等参数,尽管参数名称有所不同。
## 思维导图 {#sec-tikz-mindmap}
思维导图是非常常见的一种树状图,用于梳理层次关系。TikZ 绘制思维导图是通过 mindmap 库实现的,它是 PGF 的一个库。如 @fig-tikz-mindmap 所示,看着和脑神经网络有某种相似性,所以,有时候,思维导图也叫脑图。
``` latex
\documentclass[tikz,svgnames]{standalone}
\usepackage[fontset=fandol]{ctex}
\usetikzlibrary{mindmap}
\begin{document}
%% TikZ 代码%%
\end{document}
```
```{tikz}
#| label: fig-tikz-mindmap
#| fig-cap: TikZ 绘制思维导图
#| engine-opts: !expr list(classoption="tikz,svgnames", extra.preamble=c("\\usepackage[fontset=fandol]{ctex}","\\usetikzlibrary{mindmap}"))
\begin{tikzpicture}[
mindmap, every node/.style=concept, concept color=orange, text=white,
level 1/.append style={level distance=5cm, sibling angle=60, font=\LARGE},
level 2/.append style={level distance=3.5cm, sibling angle=45, font=\large}
]
\node{\huge{\textsf{数据分析}}} [clockwise from=60]
child [concept color=DarkMagenta] {
node {\textit{数据准备}} [clockwise from=120]
child { node {数据对象}}
child { node {数据获取}}
child { node {数据清洗}}
child { node {数据操作}}
}
child [concept color=DarkBlue] {
node {\textit{数据探索}} [clockwise from=30]
child { node {ggplot2 入门}}
child { node {基础图形}}
child { node {统计图形}}
}
child [concept color=Brown] {
node {\textit{数据交流}} [clockwise from=-30]
child { node {交互图形}}
child { node {交互表格}}
child { node {交互应用}}
}
child [concept color=teal] {
node {\textit{统计分析}} [clockwise from=-75]
child { node {统计检验}}
child { node {回归分析}}
child { node {功效分析}}
}
child [concept color=purple] {
node {\textit{数据建模}} [clockwise from=-120]
child { node {网络分析}}
child { node {文本分析}}
child { node {时序分析}}
}
child [concept color=DarkGreen] {
node {\textit{优化建模}} [clockwise from=180]
child { node {统计计算}}
child { node {数值优化}}
child { node {优化问题}}
};
\end{tikzpicture}
```
根节点视为一层,则该思维导图有三层。不同的颜色和字体来区分不同的层次或分类,数据分析划分为不同的部分,每个部分有若干章。根节点字体为黑体、第二、三级节点分别为楷体、宋体。
``` latex
\node{\huge{\textsf{数据科学}}} [clockwise from=60]
```
定义根节点,节点的文本设置为黑体,大小设置为 `\huge` 。由根节点向外辐射生成 6 个子节点,每隔 60 度设置一个子节点。
``` latex
child [concept color=DarkMagenta] {
node {\textit{数据准备}} [clockwise from=120]
child { node {数据对象}}
child { node {数据获取}}
child { node {数据清洗}}
child { node {数据操作}}
}
```
第一个子节点,颜色为饱和的紫色 DarkMagenta,二级子节点为「数据准备」,三级子节点有 4 个,逆时针 120 度的位置设置第一个三级子节点「数据对象」,然后顺时针往下,依次是「数据获取」、「数据清洗」和「数据操作」。
## SmartArt 图 {#sec-smart-diagram}
Office 办公软件中有一个 SmartArt 绘图模块,专门用来绘制各类示意图。LaTeX 宏包 [smartdiagram](https://ctan.org/pkg/smartdiagram) 基于 TikZ 定制了一套风格类似的绘图库。 smartdiagram 宏包的主要绘图命令是 `\smartdiagram[参数值]` ,设置不同的参数值可以绘制不同的图形,如气泡图 `bubble diagram` 和描述图 `descriptive diagram` 等。
```{tikz}
#| label: fig-smartdiagram-bubble
#| fig-cap: 气泡图
#| fig-width: 4
#| fig-height: 4
#| engine-opts: !expr list(extra.preamble=c("\\usepackage[fontset=fandol]{ctex}","\\usepackage{smartdiagram}"))
\smartdiagram[bubble diagram]{
Pandoc,
编程语言~\\ (Python\\R/Julia\\JavaScript),
编译引擎~\\ (Jupyter\\Knitr\\Observable),
扩展Pandoc~\\ (交叉引用\\悬浮引用\\布局面板),
文档项目~\\ (批量渲染\\共享配置),
扩展接口~\\ (RStudio\\VS Code\\JupyterLab)
}
```
```{tikz}
#| label: fig-smartdiagram-descriptive
#| fig-cap: 描述图
#| fig-width: 4
#| fig-height: 4
#| engine-opts: !expr list(extra.preamble=c("\\usepackage[fontset=fandol]{ctex}","\\usepackage{smartdiagram}"))
\smartdiagram[descriptive diagram]{
{编程语言, {Python、R、Julia、JavaScript}},
{编译引擎, {Jupyter、Knitr、Observable}},
{扩展Pandoc, {交叉引用、悬浮引用、布局面板}},
{文档项目, {批量渲染、共享配置}},
{扩展接口, {RStudio、VS Code、JupyterLab}},
}
```
## TikZ 与 R {#sec-tikz-with-r}
TikZ 绘图的优势有很多,语法简单、易于上手、功能强大、资源丰富、成熟稳定等,可以说几乎是集所有优点于一身。正因如此,**knitr** 包和 **tikzDevice** 包将其引入 R 语言社区中。**knitr** 包的 `tikz` 引擎是用来编译 TikZ 代码的,默认使用的是 standalone 文类。
R 语言绘图遇到公式时,略显不足,而排版公式是 LaTeX 的优势。正因为有所不足,所以我也不会纠结于工具层面的东西,什么好用用什么!三维 @fig-tikz-viridis 是用 LaTeX 里的优秀绘图工具 TikZ 制作的,细心的读者会发现本书多次用到这个工具。
众所周知,Donald Knuth 十年磨一剑,开发了 TeX 排版系统,就是解决排版数学公式的痛点。如 @fig-linear-model 所示,因图形中包含数学公式和符号,为了获得原汁原味的渲染效果,在使用 Base R 绘图的过程中通过 [**tikzDevice**](https://github.com/daqana/tikzDevice) 包引入了 LaTeX 中的 TikZ 绘图引擎。
```{r}
#| label: fig-linear-model
#| dev: 'tikz'
#| fig-cap: "简单线性模型"
#| out-width: "60%"
#| fig-width: 3
#| fig-height: 3
#| fig-process: !expr to_png
opar <- par(mgp = c(2, 0.7, 0), mar = c(4, 3, 4, 1) + 0.1, no.readonly = TRUE)
set.seed(2021)
x <- rnorm(10)
y <- x + rnorm(5, sd = 0.25)
lab <- sample(
x = paste0("$\\mathcal{", LETTERS, "}$"),
size = 10, replace = FALSE
)
model <- lm(y ~ x)
rsq <- summary(model)$r.squared
rsq <- signif(rsq, 4)
plot(x, y,
main = "你好 \\LaTeX!", # 引入 7 号文本字体
sub = "$\\mathcal{N}(x;\\mu,\\Sigma)$",
xlab = "$x$", ylab = "$y$", type = "n"
)
text(x = x, y = y, labels = lab)
abline(model, col = "black")
# 引入 7 号数学字体
mtext(paste("线性模型: $\\mathsf{R}^{2}=", rsq, "$"), line = 0.5)
legend("bottomright",
legend = paste0(
"$y = ", round(coef(model)[2], 3), "x +",
round(coef(model)[1], 3), "$"
),
bty = "n"
)
on.exit(par(opar), add = TRUE)
```
@fig-bessel-function 是贝塞尔函数 $\mathcal{K}_{\kappa}(u)$ 在区间 $(10^{-8}, 10^2)$ 和 $(0, 4)$ 上的图像。其中,@fig-bessel-function-1 是区间 $(10^{-8}, 10^2)$ 上的贝塞尔函数 $\mathcal{K}_{\kappa}(u)$, @fig-bessel-function-2 是区间 $(0, 4)$ 上的贝塞尔函数 $\mathcal{K}_{\kappa}(u)$ 。
```{r}
#| label: fig-bessel-function
#| fig-cap: 贝塞尔函数图像
#| fig-subcap:
#| - 区间 $(10^{-8}, 10^2)$ 上的贝塞尔函数
#| - 区间 $(0, 4)$ 上的贝塞尔函数
#| dev: 'tikz'
#| fig-process: !expr to_png
#| fig-width: 3.5
#| fig-height: 3.5
#| layout-ncol: 2
#| par: true
x0 <- 2^(-20:10)
nus <- c(2:5, 10, 20)
x <- seq(0, 4, length.out = 501)
plot(x0, x0^-8,
frame.plot = TRUE, # 添加绘图框
log = "xy", # x 和 y 轴都取对数尺度
axes = FALSE, # 去掉坐标轴
xlab = "$u$", ylab = "$\\mathcal{K}_{\\kappa}(u)$", # 设置坐标轴标签
type = "n", # 清除绘图区域的内容
ann = TRUE, # 添加标题 x和y轴标签
panel.first = grid() # 添加背景参考线
)
axis(1,
at = 10^(-8 + 2 * 0:5),
labels = paste0("$\\mathsf{10^{", -8 + 2 * 0:5, "}}$")
)
axis(2,
at = 10^(-8 + 16 * 0:4),
labels = paste0("$\\mathsf{10^{", -8 + 16 * 0:4, "}}$"), las = 1
)
for (i in seq(length(nus))) {
lines(x0, besselK(x0, nu = nus[i]), col = hcl.colors(9)[i], lwd = 2)
}
legend("topright",
legend = paste0("$\\kappa=", rev(nus), "$"),
col = hcl.colors(9, rev = TRUE), lwd = 2, cex = 1
)
x <- seq(0, 4, length.out = 501)
x <- x[x > 0]
plot(x, x,
frame.plot = TRUE, ylim = c(1e+0, 1e+20), log = "y",
xlab = "$u$", ylab = "$\\mathcal{K}_{\\kappa}(u)$",
type = "n", yaxt = "n", ann = TRUE, panel.first = grid()
)
axis(2,
at = c(1e+0, 1e+05, 1e+10, 1e+15, 1e+20),
labels = paste0("$\\mathsf{10^{", 5 * 0:4, "}}$"), las = 1
)
for (i in seq(length(nus))) {
lines(x, besselK(x, nu = nus[i]), col = hcl.colors(9)[i], lwd = 2)
}
legend("topright",
legend = paste0("$\\kappa=", rev(nus), "$"),
col = hcl.colors(9, rev = TRUE), lwd = 2, cex = 1
)
```