写在前面的后记
Beamer 这东西真不是人用的,尤其是需要进行图文排版的情况下特别难用。 所以不是要进行大量公式编辑就不要用这货了。
一些准备
我自己使用的是pdflatex
,默认是无法使用中文、日文等文字的,因此需要做一些小改动。最简单的方式是使用CJK
包,CJK
三个字母分别代表中日韩三国文字。
首先在前言部分加入\usepackage{CJKutf8}
,接着把原本的
\begin{document}
...
\end{document}
改为
\begin{document}
\begin{CJK}{UTF8}{gkai}
...
\end{CJK}
\end{document}
下面是平常可能用到的字体族的名称列表,作为参考:
ipxm
: IPAex 明朝 [日本語・明朝体]ipxg
: IPAex ゴシック [日本語・ゴシック体]gbsn
: AR PL SungtiL GB [简体中文,宋体]gkai
: AR PL KaitiM GB [简体中文,楷书]bsmi
: AR PL SungtiL GB [繁体中文,明朝体]bkai
: AR PL KaitiM GB [繁体中文,楷书]
Beamer
制作beamer
文档和制作其他LaTeX
文档的流程是一样的,只不过文件类型需要指定为beamer
:
\documentclass{beamer}
这之后可以选择主题及配色,\usetheme
改变主题,\usecolortheme
改变配色。
接着和平常一样,在前言(preamble)中加入标题×作者×日期等:
\title{开始使用beamer}
\author{我}
\date{\totay}
之后就可以开始写正文了:
\begin{document}
\maketitle
\begin{frame}{第一张幻灯片}
Hello, world!
\end{frame}
\end{document}
接着编译就能得到pdf文件啦。这里frame
相当于一张幻灯片,在frame
环境中写入的内容会出现在幻灯片中。
你应该会发现有两张幻灯片出现,第一张是由\maketitle
自动生成的。在beamerbasetitle.sty
中,\maketitle
的定义是
\def\maketitle{\ifbeamer@inframe\titlepage\else\frame{\titlepage}\fi}
这一段很容易理解,就是说如果当前位置不在frame
环境中的话那就帮你套上一个frame
环境。这也是为了和LaTeX
的语句兼容。
制作目录
和普通的LaTeX
文档一样,制作目录的过程也差不多。
现在在第二张幻灯片前加上\section{}
:
\section{开始}
再往它下方添加下面的代码:
\begin{frame}{}
\tableofcontents
\end{frame}
这样就生成了包含文件中所有section
名字的目录幻灯片。
丰富幻灯片内容
第三张幻灯片现在还基本是空的,现在往里面添加一点内容。
frame
环境中可以使用熟悉的itemize
和enumerate
,类似的还有description
。
此外,beamer
还默认内置了类似amsmath
定理环境的theorem
,lemma
,proof
,corollary
,example
等环境。
想要强调文字的时候可以使用\emph
,不过beamer
提供了更好的\alert
,会把文字显示成红色,这样看起来更加注目。
例如可以把第三张幻灯片进行如下的修改:
\begin{frame}
\frametitle{什么是质数?}
\begin{definition}
除了1和该数自身外,无法被其他自然数整除的数叫做质数。
\begin{example}
\begin{itemize}
\item 2是质数。
\item 3也是质数。
\item 4不是质数。
\end{itemize}
\end{example}
\end{definition}
\end{frame}
使用块
beamer
中有种叫block
的环境可以把文本框起来。使用方法即在block
环境中添加内容:
\begin{block}
这是block的内容。
\end{block}
制作动画
在PPT中有个很好用的功能叫动画,在beamer
中,这个功能叫overlay
,中文的意思叫覆盖。
为了方便,我还是把它叫做动画。
最简单的动画就是\pause
,稍微改动一下上面的代码:
\begin{itemize}
\item 2是质数。
\pause
\item 3也是质数。
\pause
\item 4不是质数。
\end{itemize}
这样会先显示第一个条目,然后再显示第二个,最后显示第三个。 pdf文件中可以看到原来的一张幻灯片现在变成了三张,连起来就是想要表现的动画。
制作更高级的动画
虽然\pause
简单好用,但是只能通过它做出按顺序表示的动画。
为了表现更加高级的动画,需要使用beamer
的overlay specification
功能。
在之前代码后面添加一张新的幻灯片,内容如下:
\begin{frame}
\frametitle{不存在最大质数}
\begin{definition}
不存在最大的质数。
\begin{theorem}
\begin{proof}
\begin{enumerate}
\item<1-> 设$p$为最大的质数。
\item<2-> 令$q$为$p$以及之前的所有质数的乘积。
\item<3-> 则$q+1$不会被$p$以及之前的任何一个质数整除。
\item<1-> 即$q+1$一定能被大于$p$的质数整除,与假设矛盾。
\end{enumerate}
\end{proof}
\uncover<4->{使用\alert{反证法}证明。}
\end{theorem}
\end{definition}
\end{frame}
其中<#->
这种形式的东西就是overlay specification
。
比如<2->
代表的意思就是“从第二张幻灯片开始呈现这个元素”。
\uncover
是beamer
的命令,在对文本添加overlay specification
时使用。
此外,还可以用<1>
表示只在第一张幻灯片显示,<2-4>
表示在第二到第四张幻灯片中显示等。
其他的例子还有<-3>
,<1-3,5,7>
等等。
\onslide
包围的文字或块在出现和消失时都占用同样的空间,使用方法和\pause
类似。
\begin{frame}
从第一张幻灯片开始出现
\onslide<2-3>
在第2,3幻灯片中出现
\begin{itemize}
\item 同样在第2,3幻灯片中出现
\onslide+<4->
\item 在第四张幻灯片之后出现
\end{itemize}
\onslide
在所有幻灯片上出现
\end{frame}
注意到\onslide
可以使用修饰器+
或*
。\onslide+
相当于\visible
,\onslide*
相当于\only
,没有修饰器的\onslide
相当于\uncover
。
\only{}
包含的内容在消失时完全不占空间,就像不存在一样。反而\uncover{}
包含的内容在消失和出现的时候占用同一空间。
就像名字一样,uncover
先是通过遮挡来藏住东西,然后到了指定幻灯片把遮挡移除,所以如果通过\setbeamercovered{transparent=数值}
(数值可以为0~100)的话,可以透过遮挡看到藏住的内容。
而visible
就完全不同了,它不是拿一块布遮住内容,而是直接让内容隐身,直到指定的幻灯片才让内容显示出来。
TikZ
使用beamer
有很多便利的地方,尤其是书写公式,不过同时也会带来一些麻烦,尤其是绘图这些PPT中常用的功能都没有了,做出来的效果总是非常死板,全是一条一条的目录。
这时候就需要使用TikZ
包了,借助它可以使幻灯片更加美观易读。而且beamer
本身在制作的时候就使用了TikZ
的功能,因此他们之间的关系可以说非常密切了。
首先在前言中导入TikZ
包,同时一并使用\usetikzlibrary
命令载入positioning
库,这个库主要是用来定位节点,节点在后面会提到。
\usepackage{tikz}
\usetikzlibrary{positioning}
接下来在希望绘图的位置声明tikzpicture
环境:
\begin{tikzpicture}
\end{tikzpicture}
之后只要在其中填充内容就好了。
制作树形图
首先从简单的树形图开始。在PPT中有文本框的概念,TikZ
中的节点\node
与之类似。首先配置一个树形图的根节点:
\begin{tikzpicture}
\node{root};
\end{tikzpicture}
注意TikZ
的行末需要添加分号,和C语言一样。
接下来,只需要修改节点的一些配置就可以用矩形包裹这个节点:
\node[rectangle,fill=cyan!10, text width=1.5cm, text centered, rounded corners, minimum height=1cm]{root};
其中只有fill=cyan!10
有点难以从字面上理解,这里的cyan!10
指使用10%的青色以及90%的白色来填充矩形内部。
如果要绘制多个节点的话,每次都要写这么长当然是对不重复自己原则的亵渎。因此TikZ
提供了一个别名系统,使用\tikzset
命令即可给冗长的配置起一个别名,重复采用就能变得很简单:
\tikzset{rect/.style={rectangle,fill=cyan!10,text width=1.5cm, text centered, rounded corners, minimum height=1cm}};
\node[rect]{root};
在这里定义了名为rect
的配置集合,因此之后的节点只需要调用这个别名即可。
注意:与
\tikzset
功能类似的\tikzstyle
已经不再推荐使用。
现在的树形图还只有一个根节点,使用child
语句可以制作现有节点的子节点:
\node[rect]{root}
child{node[rect]{child1}}
child{node[rect]{child2}}
child{node[rect]{child3}};
这样子节点就会被自动生成了,不过rect
样式导致节点重叠在一起,给根节点再加一点配置调整节点间的距离:
\node[rect]{root}[level distance=1.5cm, sibling distance=2cm, edge from parent/.style={<-,draw}]
child{node[rect]{child1}}
child{node[rect]{child2}}
child{node[rect]{child3}};
其中level distance
是父子节点之间的层间距离,sibling distance
是兄弟节点之间的层内距离。最后的edge from parent
是从父节点连向子节点的线,采用了<-
样式(终点指向起点的箭头)进行绘制(draw
)。
到这里,简单的树形图就完成了。当然还可以继续给子节点添加更深层的子节点:
child{node[rect]{child2}
child{node[rect]{child2-1}}
}
制作有向图
接着来制作一下有向图。 有向图中的节点一般都是圆,定义一个节点:
\begin{tikzpicture}
\node[circle, fill=cyan, text=white]{1};
\end{tikzpicture}
接下来要添加更多的节点了,不过如果只是一味增加节点的话它们都会被放到同一个位置,为了避免这种情况必须要设置节点之间的位置关系。比如第二个节点在第一个节点右上方等等:
\begin{tikzpicture}
\node[circle, fill=cyan, text=white](1){1};
\node[above right=of 1](2){2};
\end{tikzpicture}
注意在\node
命令后面添加了()
用以命名节点。接着通过above right=of 1
表现节点1的右上方。
这时候又发现了一个问题,新的节点没有设置样式。
不过之前已经知道了\tikzset
,直接起别名?当然是可以的,不过因为这里的节点全都用一样的样式,直接给所有节点设置一个默认样式会更加方便,同时再补充一些新的节点:
\begin{tikzpicture}[every node/.style={circle, fill=cyan, text=white}]
\node(1){1};
\node[above right=of 1](2){2};
\node[below right=of 1](3){3};
\node[right=1.5cm of 2](4){4};
\node[right=1.5cm of 3](5){5};
\node[below right=of 4](6){6};
\end{tikzpicture}
right=1.5cm of 2
表示节点2的右侧1.5cm处。这样所有的节点就画完了。
不过还需要把节点连起来。连线用\draw
就可以绘制,比如连接节点1,2只需要写:
\draw[->](1)--(2)
其中->
是从起点到终点的箭头,如果是无向图的话不需要这个选项。(1)--(2)
表示两个节点间的通道。
那么接下来就是一个个全部连接起来咯?当然是可以的,不过太麻烦了,这种任务用\foreach
就能一步到位。
\foreach \u / \v in {1/2,1/3,2/3,2/4,3/4,3/5,4/5,4/6,5/6}
\draw[->](\u)--(\v);
其中,\u
,\v
为循环变量,类似于Python
里面的for u,v in [(1,2), (1,3)...]
。
为公式添加标记说明
有时候在一个公式中,不同项有不同的含义,比如深度学习中的损失函数可能包含二乘误差、交叉熵、正则化项等等成分,经常会需要标记出每一个部分并添加一些描述性的文字。 比如对$f(\mathbf{w}, b)=\sum_{i=1}^{k}(y_i - \mathbf{w}^\top\mathbf{x}_i - b)^2 + \frac{\lambda}{2} | \mathbf{w} |^2$添加说明:
\begin{align*}
f(\mathbf{w}, b) =
\tikz[baseline=(1.base)]{
\node(1)[rectangle, fill=cyan!10, rounded corners]{$\displaystyle \frac{\lambda}{2} \| \mathbf{w} \|^2$} node [blue, below of=1]{正则化项};
}
\end{align*}
这里只呈现了正则化项。baseline=(1.base)
将绘制节点1的基准线与锚点(中心)对齐,这样可以避免一些莫名其妙的位置偏移。
每次写这么多太麻烦,可以用\newcommand
创建宏来处理。
\newcommand{\highlight}[2][cyan]{\tikz[baseline=(0.base)]{\node[rectangle,rounded corners,fill=#1!10](0){#2};}}
\newcommand{\highlightcap}[3][cyan]{\tikz[baseline=(0.base)]{\node[rectangle,rounded corners,fill=#1!10](0){#2} node[below of=0, color=#1]{#3};}}
第一个命令用于添加矩形块强调内容,第二个命令多了描述选项,可以在矩形块下方添加描述。[cyan]
表示缺省值,如果不指定颜色则使用青色。
利用这些宏,可以写出:
\begin{align*}
f(\mathbf{w}, b) =
\highlightcap[red]{$\displaystyle \sum_{i=1}^{k}(y_i - \mathbf{w}^\top\mathbf{x}_i - b)^2$}{经验误差}
+
\highlightcap[blue]{$\displaystyle \frac{\lambda}{2} \| \mathbf{w} \|^2$}{正则化项}
\end{align*}
注意在\highlightcap
内部需要把公式用$
包围起来。
制作气泡
和上面的矩形块不同,气泡更加自由,可以加在任何位置。
在这之前,导入一个叫做remember picture
的包,它使得tikzpicture
环境间的所有节点名称可以共享。
使用pdflatex
的话不需要显式载入包,不过也可以为了保险载入:
\usepackage{pxpgfmark}
气泡包含在shapes
库里面,因此需要使用该库:
\usetikzlibrary{shapes.callouts}
首先随便写一个东西,在此基础上添加气泡作为描述:
\tikz[remember picture]{\node(equ){$1+1=2$};}
因为气泡需要参照该节点的名字,所以一定要起节点名,如果出现奇怪的偏移的话,可以在\tikz
的选项中添加baseline=(equ.base)
。
接着来绘制气泡本身:
\begin{tikzpicture}[remember picture, overlay]
\node[rectangle callout, fill=red!50, text=white, rounded corners, callout absolute pointer={(equ.north)}, above=0.5cm of equ]{正确};
\end{tikzpicture}
overlay
表示TikZ
环境在重叠其他要素上呈现。rectangle callout
是矩形气泡。callout absolute pointer
指定气泡指向的节点坐标,这里使用的是equ.north
,即equ
节点的上端。其他 的位置设定可以查看TikZ
手册的Positioning
和Coordinate System
章节。
使用坐标绘图
除了通过指定节点的名称间接引用坐标外,还可以通过绝对坐标进行绘图。
比如二维直角坐标系中,原点可以表示成(0,0)
。此外还可以使用极坐标表示法,比如$\rho=1$,$\theta=45^\circ$可以用(30:1)
表示。
之前已经提到了路径\path
命令,大致上把它当作曲线或者直线就可以,不过实际TikZ
中的路径并不只是这样,比如可以将闭合路径内部涂上某种颜色,也可以用来剪裁别的图形。
使用坐标绘制路径:
\path (0,0) -- (0,1) -- (1,0) -- (1,1);
有中断也没关系:
\path (0,0) -- (0,1) (1,0) -- (1,1);
不过只是定义了路径还不能把它显示出来,需要加上draw
选项才能真正绘制:
\path[draw] (0,0) -- (0,1) -- (1,0) -- (1,1);
也可以使用缩略的\draw
代替\path[draw]
。还能采用各种各样的选项来定制图形:
\draw[->, red, line width=2pt] (0,0) -- (0,1) -- (1,0) -- (1,1);
除了使用坐标来绘制路径之外,也可以将其用在节点上:
\node at (0,0) {content} (nodename);
注意(0,0)
是坐标的缺省值。
在路径中间添加节点也是可以的,\node
命令实际上是\path node
的简写:
\draw[->](0,0) -- node[above]{to} (2,0);
这里的例子是在(0,0)
到(2,0)
的连线之上添加文字说明to
。通常添加的节点会放在路径的中间,但是由于添加了above
选项因此文字会被放置在上方。
当路径有倾角的时候如果想让文字说明的话需要采用sloped
选项。
\draw[->](0,0) -- node[sloped, above]{to} (3,3);
除了above
之外还可以使用left
,right
等表示一些位置关系。
上面提到过路径还能用来绘制闭合曲线并且填充颜色,这里也举一个例子:
\draw[fill=cyan, draw=none] (1,0) rectangle (2,1);
(0,0)
和(1,1)
分别是矩形左上和右下两点,fill=cyan
表示填充色,draw=none
表示不要绘制边框。当然在不需要绘制路径的时候可以不用\draw
而是直接使用\path
:
\path[fill=cyan] (1,0) rectangle (2,1);
甚至还能简化为
\fill[cyan] (1,0) rectangle (2,1);
除了明确写出两个绝对坐标来绘制矩形,也可以使用长宽作为相对值来绘制矩形:
\fill[cyan] (1,0) rectangle ++(1,1);