【科研绘图】PGF/TikZ 生成矢量图
- TikZ 介绍
- 入门教程
- TikZ 的默认坐标系统
- 基本图形对象
- 直线、矩形
- 圆、椭圆、弧
- 图形控制
- 箭头
- 线型和线宽
- 样式
- 图形变换
- 颜色和填充
- 节点
- 流程图
- 函数图像绘制
TikZ 是 PGF(Portable Graphic Format)的前端,其名称来源于德语 TikZ ist kein Zeichenprogramm,意为 TikZ is not a drawing program,是一个 GNU’s Not Unix 形式的递归缩写。
TikZ 介绍
TikZ 官网:Graphics with TikZ in LaTeX
PGF/TikZ 是一对用于 根据几何/代数描述生成矢量图形(例如技术插图和绘图)的语言,标准功能包括绘制 点、线、箭头、路径、圆、椭圆和多边形。
PGF 是较低层次的语言,而 TikZ 是一套使用 PGF 的高级宏。顶层的 PGF 和 TikZ 命令以 TeX 宏的形式调用。
TikZ 宏包 是一个十分强大的绘图宏包,它提供 \tikz
命令和 tikzpicture
环境,具体绘图指令可以放在 \tikz
后面,也可以放在 tikzpicture
中间,两者效果相同:
\tikz ... \begin{tikzpicture}
...
\end{tikzpicture}
以下图像是使用 TikZ 创建的,展示了可以生成的各种图形类型的示例。
- 函数的梯度图,源码:
- 前馈感知机,源码:
入门教程
如何开始呢,下面是一个 最小示例,使用 standalone 文档类。
\documentclass{standalone}
\usepackage{tikz}
\begin{document}\begin{tikzpicture}\draw (0,0) circle (1);
\end{tikzpicture}\end{document}
\documentclass{standalone}
就是把这个.tex
当作 “独立、可裁剪的片段” 来编译——非常适合 单张 TikZ 图 或单独的插图文件,便于模块化维护与 导出高质量、零边距的图像文件。把 每个图放在 standalone 文件里 然后 用\includestandalone{...}
插入 主文档,是一个高效的工作流。\begin{tikzpicture} ... \end{tikzpicture}
:绘图环境。\draw
:绘制路径(线、曲线、闭合区域)。
[tikz,border=6pt]
是 standalone 的便捷选项 —— tikz
自动加载 TikZ(相当于 \usepackage{tikz}
),border=6pt
设定裁剪边距。
\documentclass[tikz,border=6pt]{standalone}\begin{document}
\begin{tikzpicture}\draw (0,0) -- (1,0);
\end{tikzpicture}
\end{document}
TikZ 的默认坐标系统
TikZ 图形的上下左右由坐标值决定,不由代码行数决定。
TikZ(以及整个 LaTeX 绘图库 PGF)采用的是 数学坐标系,也就是说:
-
x
轴 向右增加; -
y
轴 向上增加。
↑ y 轴正方向
|
| (0,4)
|
| (0,3)
|
| (0,2)
|
| (0,1)
|
+----------------→ x 轴正方向
(0,0)
基本图形对象
使用 PGF 绘图的基本语法是:
\draw[option]...;
其中 \draw
称为 绘图命令;后面的 ...
部分称为 操作;而 []
是 可选项。
直线、矩形
如果要绘制一条直线,只需要在 \draw
命令 后面 输入点的坐标并使用 --
连结起来 即可。比如:
\begin{tikzpicture}\draw (1, 1) -- (2, 2) -- (3, 1);
\end{tikzpicture}
可以通过 [option]
选项 将上图中 锋利的角变成圆角,在 option
处填写 rounded corners
即可:
\begin{tikzpicture}\draw[rounded corners] (1, 1) -- (2, 2) -- (3, 1);
\end{tikzpicture}
将上图的首尾相连,成为一个 “封闭”图形。就是让最后一个点的坐标与起点相同即可:
\begin{tikzpicture}\draw[rounded corners] (1, 1) -- (2, 2) -- (3, 1) -- (1, 1);
\end{tikzpicture}
但上图并非真正意义上的封闭图形,因为那只是人为的设置了终点和起点一致而已。如果想要绘制 真正意义上的封闭图形,需要使用 cycle
操作:
\begin{tikzpicture}\draw[rounded corners] (1, 1) -- (2, 2) -- (3, 1) -- cycle;
\end{tikzpicture}
对比上图,伪封闭的图形的左下顶点并未被圆角化,而 真正封闭图形中所有角均被圆角化。
下面的的代码是 正统的绘制矩形 的方式:
\begin{tikzpicture}\draw[rounded corners] (0, 0) rectangle (2, 1);
\end{tikzpicture}
可见绘制矩形使用的是 rectangle
操作。只需要给出矩形的 一对对角顶点 然后将 rectangle
写在两者中间即可。
圆、椭圆、弧
画一个圆的命令十分的简单,给出 圆心坐标和半径,然后将 circle
操作 写在两者之间即可,注意 半径值需要用小括号括起来:
\begin{tikzpicture}\draw (0, 0) circle (1);
\end{tikzpicture}
上图绘制了一个圆心在 ( 0 , 0 ) (0, 0) (0,0) ,半径为 1 1 1 的圆。
绘制椭圆的方式也很简单,只要给出 椭圆的重心和长轴长、短轴长,然后将 ellipse
操作 写在两者中间即可,注意,长轴长和短轴长需要用括号括起来,两者之间用 and
隔开:
\begin{tikzpicture}\draw (0, 0) ellipse (2 and 1);
\end{tikzpicture}
上图绘制了一个中心在 ( 0 , 0 ) (0, 0) (0,0) ,长轴长为 2 2 2、短轴长为 1 1 1 的椭圆。
绘制圆弧或者椭圆弧只需要使用 arc
操作 并给出 相应角度 即可:
\draw (x0,y0) arc (α:β:R); % 圆弧
\draw (x0,y0) arc (α:β:Rx and Ry); % 椭圆弧
从起点 ( x 0 , y 0 ) (x_0,y_0) (x0,y0) 开始,画一个以半径 R R R 的圆弧,角度从 α α α 度到 β β β 度(按正方向,即逆时针,除非 β < α β<α β<α)。中心点由起点与起始角 α α α 和半径 R R R 唯一决定。
下面示例,
\begin{tikzpicture}\draw (1 ,1) arc (0:270:1);\draw (6 ,1) arc (0:180:2 and 1);
\end{tikzpicture}
其中,分别绘制了一个以 ( 1 , 1 ) (1, 1) (1,1) 为起点,半径为 1 1 1 的四分之三圆弧和一个中心在 ( 6 , 1 ) (6, 1) (6,1) ,长轴长为 2 2 2、短轴长为 1 1 1 的二分之一椭圆弧。
图形控制
箭头
基本格式:
\draw [〈箭头说明〉] (起点) -- (终点);
箭头符号在 [ ]
内写,可以是:
-
->
:箭头朝右(从起点指向终点) -
<-
:箭头朝左(从终点指向起点) -
<->
:两端都有箭头
以及各种变体,比如 |->
、<|-|>
、>->>
等。
一些绘制箭头的命令如下:
\begin{tikzpicture}\draw [->] (0,0)--(9,0); % 箭头朝右\draw [<-] (0,1)--(9,1); % 箭头朝左\draw [<->] (0,2)--(9,2); % 两端箭头\draw [>->>] (0,3)--(9,3); % 多个右向箭头\draw [|<->|] (0,4)--(9,4);
\end{tikzpicture}
注意,由于 y
坐标越大越“高”,在输出图像时,这些线是从下(y=0
)到上(y=4
)排列的。
线型和线宽
\begin{tikzpicture}\draw [line width =2pt] (0,0)--(9,0); %加粗实线\draw [dotted] (0,1)--(9,1); %点状虚线\draw [densely dotted] (0,2)--(9,2); %较密的点状虚线\draw [loosely dotted] (0,3)--(9,3); %较疏的点状虚线\draw [dashed] (0,4)--(9,4); %线状虚线\draw [densely dashed] (0,5)--(9,5); %较密的线状虚线\draw [loosely dashed] (0,6)--(9,6); %较疏的线状虚线
\end{tikzpicture}
样式
PGF 比较牛的一个地方是可以 自定义一些样式,这些样式一旦被定义了就可以 像面向对象的类一样被继承。也就是说可以在 导言区定义一个样式,然后可以 直接在文本区调用它。比如:
\tikzset{dline/.style ={color = red, line width =2pt}
}
\begin{document}\begin{tikzpicture}\draw[dline] (0,0) --(9,0);
\end{tikzpicture}\end{document}
图形变换
可以对图形对象进行一些变换操作,比如 缩放(scale)、平移(shift)、倾斜(slant)、旋转(rotate)、定点旋转(rotate around)等。注意 如果两种操作同时进行,它们是有顺序的。
shift={(a,b)}
:表示在绘制图形时整体平移(即把 所有坐标加上 (a,b)
)。
以正方形为例,来看看如何对它进行上述变换。首先,先来画一个正方形:
\begin{tikzpicture}\draw (0,0) rectangle (2,2);
\end{tikzpicture}
下面先对其进行 平移变换:
\begin{tikzpicture}\draw (0,0) rectangle (2,2); % (0,0) 为左下角、(2,2) 为右上角的正方形(边长 2)\draw[shift ={(3 ,0)}] (0,0) rectangle (2,2); % 向右平移 3 个单位:左下角在 (3,0),右上角在 (5,2)\draw[shift ={(0 ,3)}] (0,0) rectangle (2,2);\draw[shift ={(0 ,-3)}] (0,0) rectangle (2,2); % 向下平移 3 个单位:左下角在 (0,-3),右上角在 (2,-1)\draw[shift ={(-3 ,0)}] (0,0) rectangle (2,2);\draw[shift ={(3 ,3)}] (0,0) rectangle (2,2); % 向右上角平移 (3,3):左下角在 (3,3),右上角在 (5,5)\draw[shift ={(-3 ,3)}] (0,0) rectangle (2,2);\draw[shift ={(3 ,-3)}] (0,0) rectangle (2,2); % 向右下角平移 (3,-3):左下角在 (3,-3),右上角在 (5,-1)\draw[shift ={(-3 ,-3)}] (0,0) rectangle (2,2);
\end{tikzpicture}
还可以 指定平移方向和平移距离。xshift
表示水平平移;yshift
表示竖直平移,后面直接跟平移的距离即可(可为负数),平移距离的单位是 pt
:
\begin{tikzpicture}\draw (0,0) rectangle (2,2);\draw[xshift =70pt] (0,0) rectangle (2,2);\draw[xshift =-100pt] (0,0) rectangle (2,2);\draw[yshift =90pt] (0,0) rectangle (2,2);\draw[yshift =-120pt] (0,0) rectangle (2,2);
\end{tikzpicture}
下面再来看看缩放变换:
\begin{tikzpicture}\draw (0,0) rectangle (2,2);\draw[xshift =70pt ,xscale =1.5] (0,0) rectangle (2,2);\draw[yshift =70pt ,yscale =1.5] (0,0) rectangle (2,2);\draw[xshift =-70pt ,xscale =0.5] (0,0) rectangle (2,2);\draw[yshift =-70pt ,yscale =0.5] (0,0) rectangle (2,2);
\end{tikzpicture}
注意,缩放变换是不需要平移的!这里用了平移是为了方便一次性说明所有缩放的效果。
xscale = a
:指定 水平方向缩放 a a a 倍。若 a > 0 a>0 a>0 则代表水平方向放大(水平拉长);若 a < 0 a<0 a<0 则代表水平方向缩小(水平缩短);yscale = a
:指定 竖直方向缩放 a a a 倍。若 a > 0 a>0 a>0 则代表竖直方向放大(竖直拉长);若
a < 0 a<0 a<0 则代表竖直方向缩小(竖直缩短)scale = a
:指定 整体缩放 a a a 倍。若 a > 0 a>0 a>0 则代表整体放大;若 a < 0 a<0 a<0 则代表整体缩小。
然后是旋转变换:
\begin{tikzpicture}
\draw (0,0) rectangle (2,2);
\draw[xshift =125pt ,rotate =45] (0,0) rectangle (2,2);
\end{tikzpicture}
rotate
后面的数值写 要旋转的角度,正数表示逆时针旋转相应角度,而负数表示顺时针旋转相应角度,这与数学上的正方向规定是一致的。
如果没有指定对某个点进行旋转的话那么 默认是对起点进行旋转,上例中即为 ( 0 , 0 ) (0, 0) (0,0)。
颜色和填充
TikZ 允许通过 “颜色混合” 调节亮度:
写法 | 含义 | 说明 |
---|---|---|
red | 红色 | 纯红 |
blue!20 | 20% 蓝 + 80% 白 | 浅蓝 |
blue!80 | 80% 蓝 + 20% 白 | 深蓝 |
red!50!black | 红色和黑色各一半 | 暗红 |
green!30!yellow | 绿色+黄色混合 | 黄绿色 |
PGF 可以结合 xcolor
宏包的色彩功能。颜色和填充的用法见下例,其中 \filldraw
命令可以用不同颜色画线和填充。注意 封闭路径才可以填充!
\begin{tikzpicture}\draw[red] (0,0) --(9,0); % 红色水平线\draw[green] (0,1) --(9,1); % 绿色水平线,比红色线高一个单位\draw[blue] (0,2) --(9,2);\filldraw[draw=blue!80,fill=blue!20] (14 ,1) circle (1); % 同时填充和描边
\end{tikzpicture}
上例中如果想设置直线的颜色那么可以直接在 \draw
命令后面的 选项中填写颜色 即可。
\filldraw
命令的选项 中,draw
是为封闭图形的边界设置颜色,而 fill
是对封闭图形的内部填充颜色。
draw=blue!80,fill=blue!20
表示,描边颜色 = 蓝色 80% 强度(即较深的蓝),填充颜色 = 蓝色 20% 强度(即浅蓝、半透明感)。
节点
PGF 中的 节点 可以是简单的标签,也可以有各种形状的 边框,还可以有各种复杂的属性。比如下例中的 box
样式,它的边框是 矩形,有圆角;它有最小宽度、高度、文字和边框的距离,边框和填充颜色等属性。
\documentclass[tikz,border=6pt]{standalone}
\tikzset{box/.style ={rectangle, % 形状是矩形rounded corners =5pt, % 边角圆弧半径 5ptminimum width =50pt, % 最小宽度 50ptminimum height =20pt, % 最小高度 20ptinner sep=5pt, % 文字与边框距离draw=blue % 边框颜色为蓝色}
}\begin{document}\begin{tikzpicture}\node[box] (A) {Start};
\end{tikzpicture}\end{document}
流程图
除了上述属性,节点还可以有名字、位置等属性。在下例中,先画了三个有名字和边框的节点,也就是 文本框;然后用 两跳箭头连线 把文本框连接起来,注意连接时要引用文本框的名字;接着在连线上加了两个没有名字和边框的标签。
\begin{tikzpicture}\node[box] (1) at(0,0) {1};\node[box] (2) at(4,0) {2};\node[box] (3) at(8,0) {3};\draw[->] (1)--(2);\draw[->] (2)--(3);\node at(2,1) {a};\node at(6,1) {b};
\end{tikzpicture}
\node
命令是绘制节点,[]
还是选项,这个选项中可以填之前自定义的 box
,如果填了 box
那么就会按照 box
所定义的样式绘制节点,否则就按缺省模式绘制。
()
中写的是文本框的名字,这个名字可以随便取,{}
是文本框中的文本,- 而
at+坐标
表示的是节点所处的位置。
也可以绘制一棵树:
\begin{tikzpicture}[sibling distance =80pt]
\node[box] {1}child {node[box] {2}}child {node[box] {3}child {node[box] {4}}child {node[box] {5}}child {node[box] {6}}};
\end{tikzpicture}
child
关键字用来声明子节点;sibling distance
选项可以 控制相邻节点之间的距离,单位为 pt
。当然,也可以使用圆形节点,将 box\.style
中的 rectangle
换成 circle
并删除 rounded corners
选项,并将 minimum width
的值和 minimum height
的值设为同一个值,比如这里都设置为 20pt
:
\tikzset{box/.style ={circle, % 形状是圆形minimum width =20pt, % 最小宽度 20ptminimum height =20pt, % 最小高度 20ptinner sep=5pt, % 文字与边框距离draw=blue % 边框颜色为蓝色}
}
填充,在 box\.style
在添加一项 fill = blue!20
即可得到:
是不是感觉可以用流程图搞一个神经网络?那必须可以啊,
\begin{document}
\begin{tikzpicture}
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=blue] (1) at(0,2){$x_1$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=blue] (2) at(0,0){$x_2$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=orange] (3) at(2,-1){$a_3^{(2)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=orange] (4) at(2,1){$a_2^{(2)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=orange] (5) at(2,3){$a_1^{(2)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=orange] (6) at(4,-1){$a_3^{(3)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=orange] (7) at(4,1){$a_2^{(3)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=orange] (8) at(4,3){$a_1^{(3)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=purple] (9) at(6,2){$a_1^{(4)}$};
\node[circle,
minimum width =30pt ,
minimum height =30pt ,draw=purple] (10) at(6,0){$a_2^{(4)}$};
\draw[->] (1) --(3);
\draw[->] (1) --(4);
\draw[->] (1) --(5);
\draw[->] (2) --(3);
\draw[->] (2) --(4);
\draw[->] (2) --(5);
\draw[->] (3) --(6);
\draw[->] (3) --(7);
\draw[->] (3) --(8);
\draw[->] (4) --(6);
\draw[->] (4) --(7);
\draw[->] (4) --(8);
\draw[->] (5) --(6);
\draw[->] (5) --(7);
\draw[->] (5) --(8);
\draw[->] (6) --(9);
\draw[->] (6) --(10);
\draw[->] (7) --(9);
\draw[->] (7) --(10);
\draw[->] (8) --(9);
\draw[->] (8) --(10);
\end{tikzpicture}
可以更紧凑一些,
- 把节点样式抽成
input neuron
/hidden neuron
/output neuron
,方便统一修改大小/颜色。 - 用
\foreach
生成重复节点与连线,代码量大幅减少且容易维护。
\documentclass[tikz,border=6pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}\tikzset{neuron/.style={circle, minimum size=12mm, inner sep=0pt, draw=#1, font=\small},input neuron/.style={neuron=blue},hidden neuron/.style={neuron=orange},output neuron/.style={neuron=purple},conn/.style={->, shorten >=1pt} % 连线样式
}\begin{document}
\begin{tikzpicture}[>=Stealth]% 输入层(两个节点)\node[input neuron] (I1) at (0,2) {$x_1$};\node[input neuron] (I2) at (0,0) {$x_2$};% 隐藏层 1(3 个节点,按 y=3,1,-1)\foreach \i/\y in {1/3,2/1,3/-1}{\node[hidden neuron] (H2\i) at (2,\y) {$a_{\i}^{(2)}$};}% 隐藏层 2(3 个节点)\foreach \i/\y in {1/3,2/1,3/-1}{\node[hidden neuron] (H3\i) at (4,\y) {$a_{\i}^{(3)}$};}% 输出层(2 个节点)\node[output neuron] (O1) at (6,2) {$a_{1}^{(4)}$};\node[output neuron] (O2) at (6,0) {$a_{2}^{(4)}$};% 全连接:输入 -> 隐藏1\foreach \i in {1,2} \foreach \j in {1,2,3}{\draw[conn] (I\i) -- (H2\j);}% 隐藏1 -> 隐藏2\foreach \i in {1,2,3} \foreach \j in {1,2,3}{\draw[conn] (H2\i) -- (H3\j);}% 隐藏2 -> 输出\foreach \i in {1,2,3} \foreach \j in {1,2}{\draw[conn] (H3\i) -- (O\j);}\end{tikzpicture}
\end{document}
函数图像绘制
tikz 宏包还可以帮助绘制函数图像,比如:
\begin{tikzpicture}\draw[->] (-0.2,0) --(6,0) node[right] {$x$}; % x 轴:从点 (-0.2,0) 到点 (6,0),右端带箭头并标注 x\draw[->] (0,-0.2) --(0,6) node[above] {$f(x)$};\draw[domain =0:4] plot (\x ,{0.1* exp(\x)}) node[right] {$f(x)=\frac{1}{10}e^x$};
\end{tikzpicture}
\draw[domain=0:4] plot (...)
:画出函数曲线,其中domain=0:4
表示x
从0
到4
。(\x , {0.1 * exp(\x)})
:定义y
的函数关系: y = 0.1 × e x y = 0.1 × e^x y=0.1×ex。exp(\x)
是 TikZ 内置的指数函数(即 e x e^x ex)。node[right]{...}
:在 曲线的右端加上文字标签。