用来替换pdf
粘贴过程额外h..i
的正则表达式
\bh([\. ]+?)i\b # vscode 里面的正则, 元字符 . 需要转义成 \.
<$1>
欢迎来到TikZ
和底层pgf
系统的文档.
最初是小小的LaTeX
style, 直接用pdfLaTeX
创建我(Till Tantau)的博士论文中的图形, 现在已经发展成一个完整的图形语言, 它的手册有一千多页.
TikZ
提供的大量选项往往让初学者望而生畏;
但幸运的是, 这个文档附带了一些节奏缓慢的教程, 这些教程几乎可以教会你所有关于TikZ
的知识, 而不需要你去阅读其他的内容.
我希望从 "什么是TikZ? "这个问题开始. 基本上, 它只是定义了一些TEX
命令来绘制图形.
例如, 代码\tikz \draw (0pt,0pt) --(20pt,6pt);
产生线条. 代码\tikz \fill[orange] (1ex,1ex) circle (1ex);
产生小橙子.
在某种意义上, 当你使用TikZ
的时候, 你对你的图形进行了 "编程", 就像你在使用TEX时对你的文档进行了 "编程 "一样.
这也解释了TikZ
的名字: TikZ
是 gnu's Not Unix
传统的一个递归缩写, 即 TikZ ist kein Zeichenprogramm
,
意思是 "TikZ不是一个绘图程序", 提醒读者不要抱有错误的期待.
有了TikZ
, 你可以为你的图形获得 "TEX-approach to typesetting" 的所有优点.
快速创建简单的图形, 精确的定位, 使用宏, 通常是卓越的排版. 同时你也
你也继承了所有的缺点: 学习曲线陡峭, 没有 WYSIWYG, 小的改变需要长时间的重新编译. 而且代码并不真正 "显示 "事物的样子.
现在我们知道了TikZ
是什么, 那么 pgf
呢?
如前所述, TikZ
最初是作为一个实现TEX图形宏的项目, 它既可以用于pdfLaTeX
, 也可以用于经典的(基于PostScript
)的LaTeX
.
换句话说, 我想为TEX
实现一种 "portable graphics format"--因此被称为pgf
.
这些早期的宏仍然存在, 它们构成了本手册中描述的系统的 基本层
.
但现在文档作者的大部分互动是基于TikZ
的, TikZ
自己已经成为一门独立的语言.
page 27.
事实证明, 在TikZ
下面有两个layers
.
System layer
: 这一层提供了对驱动
中所发生的事情的完整抽象.
驱动程序是一个像dvips
或dvipdfm
这样的程序, 它接受一个 .dvi
文件作为输入, 并生成一个 .ps
或 .pdf
文件.
(pdftex
程序也算作一个驱动程序, 尽管它不接受.dvi
文件作为输入, 无所谓).
每个驱动程序都有自己的图形生成语法, 这让想以可移植方式创建图形的人感到头疼.
pgf
的系统层
抽象化了这些差异.
例如, 系统命令pgfsys@lineto{10pt}{10pt}
将当前路径扩展到当前{pgfpicture}
的坐标点(10pt, 10pt)
.
根据dvips
, dvipdfm
或pdftex
这些处理文件的具体程序, 系统命令将被转换为不同的\special
命令.
系统层尽可能地 "简约", 因为每一个额外的命令, 都会使将pgf
在移植到新的驱动程序上时需要更多的工作.
作为一个用户, 你不会直接使用系统层.
Basic layer
: 基本层提供了一组基本命令, 使你能够以比直接使用系统层更简单的方式产生复杂的图形. 比直接使用系统层要容易得多. 例如, 系统层没有提供创建圆
的命令, 因为圆
可以由更基本的贝塞尔曲线
组成(嗯...差不多). 然而, 作为一个用户, 你会希望有一个简单的命令来创建圆
(至少我是这样想). 而不是要写下半页的贝塞尔曲线的支撑坐标. 因此, 基本层提供了一个命令\pgfpathcircle
, 为你生成必要的曲线坐标.
基本层
包括一个核心
, 核心由几个相互依赖的软件包组成, 这些软件包只能被整体加载(en bloc),
还有一些额外的模块, 模块扩展核心, 以提供更多特殊用途的命令, 如node
管理或plotting
接口.
例如, beamer
包只使用核心
, 而不使用, 例如shapes
模块.
理论上, TikZ
本身只是几个可能的 frontends
之一. 它提供了命令组和一些特殊语法, 使基本层的使用更容易.
直接使用基本层的一个问题是, 用该层编写的代码往往过于 "冗长". 例如, 为了画一个简单的三角形, 你可能需要多达五个命令.
一条是在三角形的第一个角上开始一个路径. 一条用于将路径延伸到第二个角, 一条用于前往第三个角, 一条用于关闭路径.
以及一条用于实际绘制三角形的(而不是填充它).
在TikZ的前端, 所有这些都可以归结为简单的类似 METAFONT 的命令.
\draw (0,0) -- (1,0) -- (1,1) -- cycle;
实际上, TikZ
是pgf
的唯一 正式
的前端.
它让你可以使用pgf
的所有功能, 但的所有功能, 但它的目的是要使其易于使用. 语法是METAFONT
和 PSTRICKS
的混合体, 也有一些我自己的想法.
除了TikZ
之外, 还有其他的前端
, 但它们更多的是作为 "技术研究", 而不是作为TikZ
的重要替代品.
特别是pgfpict2e
, 它使用pgf
基本层, 重新实现了标准的LaTeX {picture}
环境和命令, 例如\line
或\vector
.
这个层并非真正"必要", 因为pict2e.sty
包在重新实现{picture}
环境方面至少做得很好.
相反, 这个包背后的想法是为了简单地演示如何实现一个前端.
由于大多数用户只使用TikZ
, 几乎没有人会直接使用系统层
, 所以本手册在第一部分主要是关于TikZ
的.
基础层
和系统层
将在最后解释.
p32, tikz
中, path
就是一连串的坐标, 在路径的开头可以选择:
\path
什么也不做\draw
画出路径\fill
填充路径\filldraw
等等
对路径的操作. 用分号表示一条路径的结束. 每一条路径会有初始点, 当前点等等特殊坐标.
如current subpath start
路径构建命令和绘画命令相分离, 与路径构建的选项, 都在路径命令中指定;
与实际描绘相关的选项, 都在\draw
,\fill
等命令的选项中指定.
曲线 33
\draw (0,0) .. controls (1,1) and (2,1) .. (2,0);
圆形
(1,1) circle [radius=2pt]
ellipse [x radius=20pt, y radius=10pt]
方形
\draw (0,0) rectangle (0.5,0.5);
\draw[step=.5cm] (-1.4,-1.4) grid (1.4,1.4);
自定义格式, \tikzset,p35
help lines/.style={color=blue!50,very thin} %在环境内部任意地方定义格式, 后面可以调用
\tikzset{help lines/.style=very thin} %在文档开头, 定义全局格式
\tikzset{Karl's grid/.style={help lines,color=blue!50}} %格式可以嵌套
\draw[step=.5cm,gray,very thin] (-1.4,-1.4) grid (1.4,1.4); % 使用 grid 绘制 参考格子
绘制选项, p36
%颜色
color=<color>
draw=<color>
%%线型
ultra thin
very thin
thin
semithick
thick
very thick
ultra thick
%% 虚线
dashed
loosely dashed
densely dashed
dotted
loosely dotted
densely dotted
dash pattern
剪切出图形的某一部分,clip
\draw[clip] (0.5,0.5) circle (.6cm);
\draw[step=.5cm,gray,very thin] (-1.4,-1.4) grid (1.4,1.4);
...
抛物线,parabola, p38
\tikz \draw (0,0) rectangle (1,1)(0,0) parabola (1,1);
\tikz \draw[x=1pt,y=1pt] (0,0) parabola bend (4,16) (6,12);
填充封闭区域, 使用cycle
进行封闭 39
\begin{tikzpicture}[scale=3]
\clip (-0.1,-0.2) rectangle (1.1,0.75);
\draw[step=.5cm,gray,very thin] (-1.4,-1.4) grid (1.4,1.4);
\draw (-1.5,0) -- (1.5,0);
\draw (0,-1.5) -- (0,1.5);
\draw (0,0) circle [radius=1cm];
\filldraw[fill=green!20!white, draw=green!50!black] (0,0) -- (3mm,0mm)
arc [start angle=0, end angle=30, radius=3mm] -- cycle;
\end{tikzpicture}
渐变色,shade,p39
\shadedraw[left color=gray,right color=green, draw=green!50!black](0,0) -- (3mm,0mm)
定义命令, 相对坐标指定, p40
(30:1cm |- 0,0) % 垂直线与水平线的交点, |- 左边的坐标对应铅垂线, 右边的对应水平线.
\def\rectanglepath{-- ++(1cm,0cm) -- ++(0cm,1cm) -- ++(-1cm,0cm) -- cycle} %% 连续的相对指定, 后一个坐标相对于前一个, 使用 \def 在任意地方定义一个命令替换.
\def\rectanglepath{-- +(1cm,0cm) -- +(1cm,1cm) -- +(0cm,1cm) -- cycle} %% 基于相同root的相对坐标, 后面几个坐标相对于同一个最初坐标
路径的交点, 使用name path
在后面引用.
可以使用(1,{tan(30)})
这种坐标形式, tikz
的数学引擎可以处理tan(30)
, 但是外面需要包围一层{}
, 否则会与坐标的语法冲突. 一般情况中, 遇到含有()
的坐标, 也需要用{}
包裹起来.
% 在导言区 \tikz 后面添加 \usetikzlibrary{intersections}
\path [name path=upward line] (1,0) -- (1,1); % 给第一条路径命名, \path 只计算路径, 不进行实际描绘.
\path [name path=sloped line] (0,0) -- (30:1.5cm); % 第二条路径, 画得稍微长一点, 保证有交点
\draw [name intersections={of=upward line and sloped line, by=x}] [very thick,orange] (1,0) -- (x);
添加箭头, 通过->
选项, 可以指定在路径末端加上箭头.
\usetikzlibrary {arrows.meta}
\begin{tikzpicture}[>=Stealth]
\draw [->] (0,0) arc [start angle=180, end angle=30, radius=10pt];
\draw [<<-,very thick] (1,0) -- (1.5cm,10pt) -- (2cm,0pt) -- (2.5cm,10pt);
\end{tikzpicture}
参考p42, scope. 类似于其他程序中的局部变量. 在导言区添加\usetikzlibrary {scopes}
.
例如在tikzpicture
环境中使用tikz-feynman
包的feynman
环境定义的fermion
edge style.
\begin{tikzpicture}
{[every edge/.style={controls=+(27:3) and +(153:3), /tikzfeynman/fermion}]
\path (0,0) edge (0,1);
} % 末尾无需分号
\end{tikzpicture}
every edge/.style
是tikzpicture
环境中的handle
.
可以给选项设置作用范围, 如果想让整个环境都生效, 可以把选项传递给\tikz
命令或者{tikzpicture}
环境.
如果希望定义一个局部环境, 可以使用{scope}
环境. 例如:
\begin{tikzpicture}[ultra thick]
\draw (0,0) -- (0,1);
\begin{scope}[thin] % 在这里给出选项
\draw (1,0) -- (1,1);
\draw (2,0) -- (2,1);
\end{scope}
\draw (3,0) -- (3,1);
\end{tikzpicture}
\clip
的生效范围也受\scope
的控制, 只在scope
范围内有效.
类似于\draw
的选项, 其实不是\draw
的选项, 而是提供给path
的选项, 可以在路径命令序列的任何地方提供. 大部分graphic
选项是对整个路径生效的, 所以选项的位置不重要.
例如, 下面三种用法是等价的. 如果同时给出thick
and thin
, 后一个覆盖前一个的效果.
\begin{tikzpicture}
\draw[thin] (0,0) --(1,0);
\draw (0,1) [thin] --(1,1);
\draw (0,2) --(1,2) [thin];
\end{tikzpicture}
大部分图形选项应用于整个路径, 而所有的变形选项,transformation
只作用于跟在其后的路径片段.
page 43. 路径变形选项.
图像的最后位置是由TikZ
, TeX
, PDF
共同决定的. tikz
提供了一些选项可以在自己的坐标系统内变换图像的位置. 并且运行在路径中途修改变换方式. 例如:
\begin{tikzpicture}[even odd rule,rounded corners=2pt,x=10pt,y=10pt]
\filldraw[fill=yellow!80!black] (0,0) rectangle (1,1) [xshift=5pt,yshift=5pt] (0,0) rectangle (1,1) [rotate=30] (-1,-1) rectangle (2,2);
\end{tikzpicture}
这类选项有:
x=<value>
, y=<value>
, z=<value>
. 例如:
\draw[x=2cm,color=red] (0,0.1) -- +(1,0);
\draw[x={(2cm,0.5cm)},color=red] (0,0) -- (1,0); %含有逗号的坐标需要放在括号里 escape
xshift=<dimension>
,yshift=<dimension>
:用来平移shift={<coordinate>}
: 平移到指定的点, 如shift={(1,0)}, shift={+(1,0)},
必须加上{}
, 以避免TeX
把坐标解析成两个选项. 例如:
\draw[shift={(1,1)},blue] (0,0) -- (1,1) -- (1,0);
\draw[shift={(30:1cm)},red] (0,0) -- (1,1) -- (1,0);
rotate=<degree>
: 旋转特定角度. 以及rotate around
:绕指定的点旋转.scale=<factor>
: 放大或者缩小指定的倍数. 以及xscale
,yscale
.xscale=-1
表示翻转.xslant=<factor>
,yslant=<factor>
: 倾斜cm
: 指定任意的变换矩阵.
详细可以参考 page 373: 25 Transformations
latex
本身有循环的命令, pstricks
具有\multido
命令. tikz
也引入了自己的循环命令\foreach
, 它定义在\pgffor
中, \tikz
会自动\include
这个命令.
语法是\foreach \x in {1,2,3} {$x =\x $,}
. 循环区域用列表指定, 要循环的指令也放在一个{}
中. 如果不用{}
包裹, 就把下一个;
之前的命令当作循环指令. 例如下面的语句绘制一个坐标系:
\begin{tikzpicture}[scale=3]
\draw[step=.5cm,gray,very thin] (-1.4,-1.4) grid (1.4,1.4);
\draw[->] (-1.5,0) -- (1.5,0);
\draw[->] (0,-1.5) -- (0,1.5);
\foreach \x in {-1cm,-0.5cm,1cm}
\draw (\x,-1pt) -- (\x,1pt);
\foreach \y in {-1cm,-0.5cm,0.5cm,1cm}
\draw (-1pt,\y) -- (1pt,\y);
\end{tikzpicture}
也可以结合平移使用:
\foreach \x in {-1,-0.5,1} \draw[xshift=\x cm] (0pt,-1pt) -- (0pt,1pt);
\foreach
也可以使用c
式的范围指定: {a,...,b}
, 必须使用无量纲的实数. {1,3,...,11}
则可以指定步长. 两种语法可以混合, 例如:
\tikz \foreach \x in {1,3,...,11} \draw (\x,0) circle (0.4cm);
循环可以嵌套:
\begin{tikzpicture}
\foreach \x in {1,2,...,5,7,8,...,12}
\foreach \y in {1,...,5}
{
\draw (\x,\y) +(-.5,-.5) rectangle ++(.5,.5);
\draw (\x,\y) node{\x,\y};
}
\end{tikzpicture}
为了方便, 还有一种key/value
型的循环语法: foreach \key/\value in {1/a,2/b,3/c}
, key/value
用/
分隔开. 在每一次循环中, \key
和\value
的值将一一对应.
如果循环域中, 某一项只给出了key
, 会默认value
等于key
.
添加文字可以使用\node
命令, 也可以用来添加任意形状. 通常的用法是\node[选项]{文字}
. \node
会放在当前位置, 也就是\node
命令前面的那个坐标上.
当所有路径draw/fill/shade/clipped/whatever
完成之后, 才绘制\node
, 所以\node
的图层在最上面.
- 可以使用类似于
anchor=north
指定\node
的哪一个锚点放在前面给定的坐标上. 也可以使用below=1pt
直接指定\node
的相对偏移. - 如果担心图形上的其他元素干扰了
node
的辨识度, 可以给node
加上[fill=white]
选项, 绘制一个白色的背景. - 如果把
\node
放在--
后面, 默认会将\node
的位置放在这条线段的中点. 可以使用pos=
选项控制具体的位置, 也可以使用near start
,near end
等等指定大概位置. - 还可以使用
[above, sloped]
选项, 使曲线上方的\node
贴合曲线斜率. 例如:
\begin{tikzpicture}
\draw (0,0) .. controls (6,1) and (9,1) ..
node[near start,sloped,above] {near start} node {midway}
node[very near end,sloped,below] {very near end} (12,0);
\end{tikzpicture}
如果\node
中的文本量比较大, 需要控制换行, 可以使用类似text width=6cm
的选项控制\node
宽度. 完整的例子为:
\begin{tikzpicture}
[scale=3,line cap=round,
% 定义一些对象的格式
axes/.style=,
important line/.style={very thick},
information text/.style={rounded corners,fill=red!10,inner sep=1ex}]
% 定义一些对象的颜色
\colorlet{anglecolor}{green!50!black}
\colorlet{sincolor}{red}
\colorlet{tancolor}{orange!80!black}
\colorlet{coscolor}{blue}
% 开始画图
\draw[help lines,step=0.5cm] (-1.4,-1.4) grid (1.4,1.4);
\draw (0,0) circle [radius=1cm];
\begin{scope}[axes]
\draw[->] (-1.5,0) -- (1.5,0) node[right] {$x$} coordinate(x axis);
\draw[->] (0,-1.5) -- (0,1.5) node[above] {$y$} coordinate(y axis);
\foreach \x/\xtext in {-1, -.5/-\frac{1}{2}, 1}
\draw[xshift=\x cm] (0pt,1pt) -- (0pt,-1pt) node[below,fill=white] {$\xtext$};
\foreach \y/\ytext in {-1, -.5/-\frac{1}{2}, .5/\frac{1}{2}, 1}
\draw[yshift=\y cm] (1pt,0pt) -- (-1pt,0pt) node[left,fill=white] {$\ytext$};
\end{scope}
\filldraw[fill=green!20,draw=anglecolor] (0,0) -- (3mm,0pt)
arc [start angle=0, end angle=30, radius=3mm];
\draw (15:2mm) node[anglecolor] {$\alpha$};
\draw[important line,sincolor]
(30:1cm) -- node[left=1pt,fill=white] {$\sin \alpha$} (30:1cm |- x axis);
\draw[important line,coscolor]
(30:1cm |- x axis) -- node[below=2pt,fill=white] {$\cos \alpha$} (0,0);
\path [name path=upward line] (1,0) -- (1,1);
\path [name path=sloped line] (0,0) -- (30:1.5cm);
\draw [name intersections={of=upward line and sloped line, by=t}]
[very thick,orange] (1,0) -- node [right=1pt,fill=white]
{$\displaystyle \tan \alpha \color{black}=
\frac{{\color{red}\sin \alpha}}{\color{blue}\cos \alpha}$} (t);
\draw (0,0) -- (t);
\draw[xshift=1.85cm]
node[right,text width=6cm,information text]
{
The {\color{anglecolor} angle $\alpha$} is $30^\circ$ in the
example ($\pi/6$ in radians). The {\color{sincolor}sine of
$\alpha$}, which is the height of the red line, is
\[
{\color{sincolor} \sin \alpha} = 1/2.
\]
By the Theorem of Pythagoras ...
};
\end{tikzpicture}
pic
是picture
的简称. 通过预先定义的图片名字, 可以在指定的地方复用图形. 例如:
\usetikzlibrary {angles,quotes}
\begin{tikzpicture}[scale=3]
\coordinate (A) at (1,0);
\coordinate (B) at (0,0);
\coordinate (C) at (30:1cm);
\draw (A) -- (B) -- (C)
pic [draw=green!50!black, fill=green!20, angle radius=9mm,"$\alpha$"] {angle = A--B--C};
\end{tikzpicture}
这里调用了angles
and quotes
库. 前者预定义了angle
图形, 后者可以简化参数输入为"标记"
, 而不需要输入label text="标记"
.
{angle = A--B--C}
表示angle
是BA
和BC
的夹角. \coordinate
用于声明一个坐标点, 可以在后文引用.
page 124, TikZ
遵循以下基本设计原则:
- 用于指定
points
的特殊语法. - 指定
path
的特殊语法. - Actions on paths.
- 图形参数的
Key–value
语法. nodes
的特殊语法.trees
的特殊语法.graphs
的特殊语法.- 对图形的参数分组.
- 坐标转换系统.
131 Using Scopes to Structure a Picture. 如果scope
不生效的话, 可以尝试在导言区添加
\usetikzlibrary {scopes}
命令 \path
用于创建一个路径 (path
),此命令可以带有图形选项 (graphic options),这些选项只对本路径有效. 使用简写形式的 scope 可以在路径内部插入一个 scope
:
\tikz \draw (0,0) -- (1,1)
{[rounded corners, red] -- (2,0) -- (3,1)}
-- (3,0) -- (2,1);
上面例子中,选项 rounded corners
的作用范围受到花括号的限制,并且颜色选项 red 没有起到作用,这是因为 \draw
的默认颜色是 draw=black
,颜色 black
把 red
覆盖了.
还要注意开启 scope 的符号组合{[...]
要放在坐标点之后, --
之前.
除了\tikzpicture
环境, 可以使用简洁的\tikz{path1;path2}
命令, 例如:
\tikz[baseline]{
\draw (0,0)--(2,0);\draw (0.5,0) to [out=90,in=90,looseness=1.5] (1.5,0);
\draw (0.5,0) to [out=-90,in=-90,looseness=1.5] (1.5,0);
}
page 148
page 136, Specifying Coordinates page 148,TikZ Library calc, 可以计算坐标值.
坐标总是放在圆括号内, 一般的语法是 ([<options>]<coordinate specification>)
. 有两种指定坐标的方法:
明确指定坐标系统和参数, 使用xxx cs:
这种语法
\draw (canvas cs:x=0cm,y=2mm)
-- (canvas polar cs:radius=2cm,angle=30);
或者可以隐式地指定, tikz
会根据格式自动判断坐标系统. 例如 (0,0)
对应笛卡尔坐标,(30:2)
对应极坐标 (其中 30
代表角度).
- 基本使用:
(1cm,2pt)
- 极坐标:
(30:1cm)
PGF-xy
坐标系统, 单位按照cm
:(2,1)
PDF-xyz
坐标系统:(1,1,1)
- 也可以使用利用之前定义的形状作为锚点,如:
(first node.south)
- 连续相对坐标:
++(1cm,0pt)
,(1,0), ++(1,0), ++(0,1)
给出(1,0), (2,0),(2,1)
- 同源相对坐标:
+(1,0) +(1,0) +(0,1)
给出(1,0), (2,0), (1,1)
.
对图像进行全局伸缩, 可以指定xyz
单位矢量的长度, 也可以通过画布变换
page 137: Coordinate system xyz page 43: Transformations
路径是一些直线和曲线的组合.
部分使用metapost
的语法,例如,一条三角形路径
(5pt,0pt) -- (0pt,0pt) -- (0pt,5pt) -- cycle
p168 The Let Operation
路径只是一系列直线和曲线的组合,但你尚未指定如何处理它. 可以绘制一条路径,填充一条路径,为其着色,对其进行裁剪或进行这些操作的任意组合.
draw
,fill
,shade
,clip
例如
\path[draw] (0,0) rectangle (2ex,1ex)
\path[draw]
: \draw
\path[fill]
:\filldraw
\path[shade]
:\shade
and \shadedraw
\path[clip]
:
\draw[clip]
or \path[draw,clip]
: \clip
所有这些命令只能在{tikzpicture}
环境中使用. TikZ
允许您使用不同的颜色进行填充和描边.
\begin{tikzpicture}[abcde/.style={
double distance=10pt,
postaction={
decorate,
decoration={
markings,
mark=at position .5 with {\arrow[blue,line width=1mm]{>}},
}
}
}]
\begin{feynman}
...
\end{feynman}
\draw [help lines] grid (3,2);
\draw[abcde] (a1) -- (b1);
\end{tikzpicture}
173 Graphic Parameters: Line Width, Line Cap, and Line Join
/tikz/dash pattern=<dash pattern>
/tikz/dashed
: 指定虚线模式的简写
Shorthand for setting a dashed dash pattern.
p224, Nodes and Their Shapes
比如
\begin{tikzpicture}
\draw (0,0) node[minimum size=2cm,draw] {square};
\draw (0,-2) node[minimum size=2cm,draw,circle] {circle};
\end{tikzpicture}
p785: 72 Shape Library, 形状库
p229: 17.2.3 Common Options: Separations, Margins, Padding and Border Rotation: 给出了 node
一些几何参数的选项
p730: 63 Pattern Library : node
可以使用 pattern
填充, 某种图形模式.
p191 Arrows 箭头
p196 指定箭头大小, 形状
p212 Reference: Arrow Tips 与定义箭头形状参考
\usetikzlibrary{arrows.meta}
p365 Decorated Paths 装饰路径
p646 Arbitrary Markings 添加任意装饰
Decoration markings
marking
可以被认为是"小图片", 或更准确地说是放置的some scope contents
, 放置在路径的某个位置"上".
假设marking
为简单的十字. 可以用以下代码产生:
\draw (-2pt,-2pt) -- (2pt,2pt);
\draw (2pt,-2pt) -- (-2pt,2pt);
如果我们将此代码用作路径上2cm
处的marking
, 则会发生以下情况:
pgf
先确定沿路径2cm
的位置. 然后将坐标系平移到此处并旋转它, 使x
轴正向与路径相切. 然后创建一个保护用的scope
, 在内部执行上述代码--最后路径上出现一个叉叉.
marking
允许在路径上放置一个或多个装饰. 除了后面讲的少数情况, decoration
摧毁路径输入, 也就是说, 计算完成, 作完装饰之后, 路径就消失了. 一般需要postaction
来添加装饰.
postaction
表示完成路径绘制之后再进行操作.
\begin{tikzpicture}[decoration={
markings,% 启用 markings
mark=% mark 的形状
at position 2cm
with
{
\draw (-2pt,-2pt) -- (2pt,2pt);
\draw (2pt,-2pt) -- (-2pt,2pt);
}
}
]
\draw [help lines] grid (3,2);
\draw [postaction={decorate}] (0,0) -- (3,1) arc (0:180:1.5 and 1); % postaction 表示画完路径之后再装饰, 再摧毁路径.
\end{tikzpicture}
p263, pic
是picture
的简称. 通过预先定义的图片名字, 可以在指定的地方复用图形. 例如先定义一个海鸥的形状:
\tikzset{
seagull/.pic={
% Code for a "seagull". Do you see it?...
\draw (-3mm,0) to [bend left] (0,0) to [bend left] (3mm,0);
}
}
使用\tikzset
定义的是全局的, 整个文档都可以调用. 然后调用它:
\tikz \fill [fill=blue!20]
(1,1)
-- (2,2) pic {seagull}
-- (3,2) pic {seagull}
-- (3,1) pic [rotate=30] {seagull}
-- (2,1) pic [red] {seagull};
如pic
命令说明中所述, 要定义新的pic
类型, 您需要
- 定义一个路径前缀为
/tikz/pics
的key
, - 将
/tikz/pics/code
设置为pic
的code
.
这可以使用.style
handler 实现:
\tikzset{
pics/seagull/.style ={
% 当调用 seagull 的时候, 下面的代码会设置 seagull 的 code key:
code = { %
\draw (...) ... ;
}
}
}
一些简单的情况下, 可以直接使用.pic
handler,
\tikzset{
seagull/.pic = {
\draw (...) ... ;
}
}
此handler
只能对带有/tikz/
前缀的key
一起使用, 因此通常应将其用作TikZ
命令或\tikzset
命令的选项.
它使用<key>
的路径, 并把其中的/tikz/
替换为/tikz/pics/
. 最终得到一个style
, 能够执行code = some code
.
大多数情况下, .pic
handler足以设置keys
. 但是, 在某些情况下确实需要使用第一个版本:
- 当您的图片类型需要设置
foreground
或background
代码时. - 如果给
key
提供了复杂的参数
例如:
\tikzset{
pics/my circle/.style = {
background code = { \fill circle [radius=#1]; }
}
}
\tikz [fill=blue!30]
这里给my circle
使用了参数.
<key>/.code n args={<m>}{<代码>}
:传入m
个参数{#1}{#2}{#3}...
,m
为0~9
, 不能多也不能少, 空格也可以作为参数.
page 269; 19 Specifying Graphs
在本节中, 我们所说的图是指一组结点和一些边(有时也称为弧, 取决于连接方式), 如下面的图. 例如:
\usetikzlibrary {graphs}
\tikz \graph { a -> {b, c} -> d };
图的结点是正常的TikZ
节点, edge
也是节点之间普通的连线. graphs
库中没有任何东西是你不能用普通的 \node
和edge
命令来做的.
它的主要优势是只需指定哪些节点和边是存在的. 在画布为节点上寻找 "好位置 "的问题留给了图形绘制算法
.
算法在本手册的第四部分描述, 这些算法不是graphs
库的一部分;
事实上, 这些算法也可以优化edge
和node
命令创建的图形, 而不需要调用graphs
库.
例如可以 load layered
图形绘制库, 使用\tikz[layered layout,...
, 然后使用LuaTeX
编译, 同样可以得到较好的排版.
画graph
的基本方法是写出一个节点链,
\usetikzlibrary {graphs}
\tikz [every node/.style = draw]
\graph { foo -> bar -> blub;a -> b -> c;};
节点文字和->
交替排列, ->
算符用来产生箭头. 多条链之间用分号;
或逗号,
分隔.
节点名称默认等于其中的文字. 可以显式更改这种设定. 通过as
key, 或者在节点后面加上slash/
.
\usetikzlibrary {graphs}
\tikz \graph {
x1/$x_1$ -> x2 [as=$x_2$, red] -> x34/{$x_3,x_4$};
x1 -> [bend left] x34;
};
要使用特殊符号当作节点的名字,如,
或虚线, 需要用引号"
包裹. 例如
\usetikzlibrary {graphs}
\tikz \graph {
"$x_1$" -> "$x_2$"[red] -> "$x_3,x_4$";
"$x_1$" ->[bend left] "$x_3,x_4$";
};
可以把多条chain
放在一个{}
中, 形成一个 chain group. 这样可以实现同时连接多个node.
前一个node
或者group
的exit points
将连接到后一个node
or group
的entry points
.
\usetikzlibrary {graphs}
\tikz \graph {
a -> { b -> c, d -> e} -> f};
树形图可以通过添加tree layout
来使图形更加美观. 同时需要在导言区加上
\usetikzlibrary {graphdrawing}
\usegdlibrary {trees}
可以给->
connector 提供选项, 来定制风格.
\usetikzlibrary {graphs}
\tikz \graph {
a ->[red] b --[thick] {c, d};
};
使用quotes
语法, see Section 17.10.4, 可以方便的添加标签:
\usetikzlibrary {graphs,quotes}
\tikz \graph {
a ->[red, "foo"] b --[thick, "bar"] {c, d};
};
如果想给不同的edge
指定不同的标签, 可以去掉给--
提供的选项, 转而给node
提供选项.
用>
来表示进入node
的edge
, 用<
表示从node
出射的edge
.
\usetikzlibrary {graphs,quotes}
\tikz \graph {
a [< red] -> b -- {c [> blue], d [> "bar"']};
};
"bar"'
后面的单引号'
表示翻转标签bar
的位置到下面. 使用这种语法可以创建带有特殊标签的树图.
\usetikzlibrary {graphs,quotes}
\tikz
\graph [edge quotes={fill=white,inner sep=1pt},
grow down, branch right, nodes={circle,draw}] {
"" -> h [>"9"] -> { c [>"4"] -> { a [>"2"], e [>"0"] },j [>"7"]}
};
当你在graph
命令中写下节点
文本时, 默认会创建一个新的节点, 除非这个节点已在同一个图形命令创建过.
特别是, 如果节点已经在graph
的范围外声明过, 则会创建一个同名的新节点. 这并不总是理想的行为.
你可能希望使用已经定义好的节点画新的graph
, 而不是在graph
内部重新定义.
为此, 只需在节点名称周围加上圆括号()
. 这将导致创建对已经存在的节点的引用
.
\usetikzlibrary {graphs}
\tikz {
\node (a) at (0,0) {A};
\node (b) at (1,0) {B};
\node (c) at (2,0) {C};
}
\graph { (a) -> (b) -> (c) };
你甚至可以更进一步. 一群节点可以通过添加选项set=<node set name>
来标记为属于一个节点集
.
然后, 在graph
命令中, 你可以通过在节点集
名称的周围加上括号()
, 来引用这些节点.
\usetikzlibrary {graphs,shapes.geometric}
\tikz [new set=my nodes] {
\node [set=my nodes, circle, draw] at (1,1) {A};
\node [set=my nodes, rectangle, draw] at (1.5,0) {B};
\node [set=my nodes, diamond, draw] at (1,-1) {C};
\node (d)[star, draw] at (3,0) {D};
\graph { X -> (my nodes) -> (d) };
}
由于图形中经常存在重复使用的部分, 为了便于指定这样的图形, 你可以定义图形宏
.
一旦定义了图形宏
, 你就可以使用图形的名称来复制它.
\usetikzlibrary {graphs.standard}
\tikz \graph { subgraph C_n [n=5, clockwise] -> mid };
graphs.standard
库定义了许多这样的图,
包括n
个节点上的 complete bipartite graph Kn,m
, 具有shores sized n
和m
, n
个节点上的循环Cn
, n
个节点上的路径Pn
,
以及n
个节点上的独立集合In
.
当使用graph
命令构建图时, 它递归构建的, 将较小的图拼成较大的图.
在这个递归的拼合过程中, 图的节点会被隐含
地着色 (概念上), 你也可以显式地为单个节点指定颜色, 甚至可以在指定(specify)图形时改变颜色.
所有具有相同颜色的节点形成一个所谓的颜色类
(color class).
颜色类
的强大之处在于, 特殊的连接运算符
(connector operator)允许你在具有特定颜色的节点之间添加边.
例如, 在组的开头添加clique=red
会使所有的节点被标记为(概念上)红色
, 这些节点将会被连接成一个clique
.
同样地, complete bipartite={red}{green}
将在所有red
节点和所有green
节点之间增加边.
更高级的connector
, 比如蝴蝶 connector
, 允许你以一种花哨的方式在颜色类
之间添加边.
\usetikzlibrary {graphs}
\tikz [x=8mm, y=6mm, circle]
\graph [nodes={fill=blue!70}, empty nodes, n=8] {
subgraph I_n [name=A] --[butterfly={level=4}]
subgraph I_n [name=B] --[butterfly={level=2}]
subgraph I_n [name=C] --[butterfly]
subgraph I_n [name=D] --
subgraph I_n [name=E]
};
164 The To Path Operation 838 To Path Library page 841 75.4 Loops
- 可以使用
To
来绘制直线, 也可以用来绘制曲线.
\path ... to[<options>] <nodes> <coordinate or cycle> ...;
例如(a) to [out=135,in=45] (b)
各种选项
/tikz/out=<angle>
/tikz/in=<angle>
...
在给定出射和入射角度之后, /tikz/looseness=<number>
选项中的<number>
调控control points
与初始点以及与终点的距离.
还可以用 /tikz/min distance=<distance>
, /tikz/out min distance=<distance>
控制最小距离, 避免计算无解.
- 使用
loop
选项来绘制圈图曲线, 例如
\begin{tikzpicture}
\begin{feynman}
\draw (0,0) edge [anti charged scalar,loop, looseness=30] (h3);
\end{feynman}
\end{tikzpicture}
loop
选项只接受一个参数, 即初始点, 终点位置和初始点相同, 然后把looseness
设置为8
, min distance
设置为5mm
.
如果想精确控制圈图的形状, 可以手动添加控制点, 例如:
\draw (a3) to [controls=+(45:1.5) and +(135:1.5)] (a3);
上面使用+(角度:距离)
的方式指定控制点的坐标, and
左右的坐标采用相对坐标的形式, 分别相对于路径的起点
和终点
.
参考 page 33, 可以使用to
的简称, 即..
语法以 曲线
方式延伸路径:
.. controls <控制点1> and <控制点2> .. <终点>
你可以省略and <控制点2>
, 这将导致使用控制点1
两次.
如果要使用tikz-feynan
定义的线型, 使用下面的edge
, 并使用tikz-feynan
定义的全称, 例如:
\draw (a3) edge [controls=+(30:3) and +(150:3), /tikzfeynman/fermion] (a4);
17.12 Connecting Nodes: Using the Edge Operation
edge(边)
操作的作用类似于主路径绘制完成后添加的to
操作, 就像node
是在主路径绘制完成后添加的.
这样, 每条边就可以有不同的外观.
和node
操作一样, edge
的操作会暂时中止当前路径的构建, 并构建一个新的路径p
.
这个新的路径p
将在主路径绘制完毕后被绘制. 请注意, p
可以与主路径的选项完全不同.
还要注意的是, 如果主路径中有几个edge
或node
操作, 每个操作都会创建自己的路径, 并且按照它们在主路径上出现的顺序来绘制.
\path … edge[<options>] <nodes> (<coordinate>) …;
edge
操作的效果是, 在主路径之后, 下面的路径被添加到图片中:
\path[every edge,<options>] (\tikztostart) <path>;
这里, <path>
是to path
. 注意, 与to
操作所添加的路径不同, (\tikztostart)
被添加到<path>
之前,
这对to
操作来说是不必要的, 因为这个坐标已经是主路径的一部分.
\tikztostart
是edge
操作之前的路径上的最后一个坐标, 就像对node
或to
操作一样.
然而, 这条规则有一个例外: 如果edge
操作的前面是node
操作, 那么这个刚刚声明的node
就是起始坐标.
而不是像通常情况下那样, 是这个节点所处的坐标--一个微妙的区别. 在这方面, edge
与node
和to
都不同.
如果一行有多个edge
操作, 那么所有这些操作的起始坐标都是一样的, 但是目标坐标不同, 它们是主路径的一部分.
因此, 起始坐标就是第一个edge
操作之前的坐标. 这一点与node
类似, edge
操作也不会修改当前路径.
特别是, 它不改变最后访问的坐标, 见下面的例子:
\begin{tikzpicture}
\node (a) at (0:1) {$a$};
\node (b) at (90:1) {$b$} edge [->] (a);
\node (c) at (180:1) {$c$} edge [->] (a)
edge [<-] (b);
\node (d) at (270:1) {$d$} edge [->] (a)
edge [dotted] (b)
edge [<-] (c);
\end{tikzpicture}
159 The Arc Operation
\path ... arc[<options>] ...;
从当前点开始画弧线, 可以用x radius
and y radius
指定半径, 用start angle
, end angle
, and delta angle
指定角度.
也有一个较简捷的句法来指定圆弧:
arc(<start angle>:<end angle>:<radius>)
或者
arc(<start angle>:<end angle>:<x radius> and <y radius>)
tikz-feynman
包中的顶点相当于node
, node
的特点是需要添加文字(可以为空白--{}
), 也就是类似下面这种. 在node
周围会留下空白, 其实是node
占据的空间.
\node[above right =0.7 and 4.2 of a1] {text}
参考 p229, 17.2.2 Predefined Shapes.
如果不想画出node
, 只是给坐标分配名称, 例如(x)
, 并希望传播子可以直接连接(x)
. 可以使用coordinate
.
它的效果类似于使用了(x.center)
, 不会把路径断开成几段. 可以完整的连接起来, 或者给包围的区域上色.
类似于
\coordinate[right =2.2 of a1] (a3); % 泡泡起点
这样后面不需要有{text}
.
p224 基本语法:
\path ... node <foreach statements> [<options>] (<name>) at (<coordinate>) : <animation attribute>
={<options>} {<node contents>} ...;
各部分规范的顺序. 在node
和{<node contents>}
之间的所有内容都是可选的. 如果有<foreach>
语句,它必须首先出现,紧接在node
之后.
除此之外,节点规范的所有其他元素( <options>
,name
,coordinate
和 animation attribute
)的顺序都是任意的,
实际上,这些元素中的任何一个都可能多次出现(尽管对于name
和coordinate
,这没有意义).
例如
\vertex (a2) at (0,0){2};
at
p158
\path ... circle[<options>] ...;
/tikz/at=<coordinate>
如果在<options>
内部显式设置了此选项(或通过every circle
样式间接设置), 则<coordinate>
将用作圆的中心而不是当前点. 在一个封闭范围内给某个值设置at
无效.
page 785,72 Shape Library: 可以指定node
的形状, 有预定义的各种形状.
page 563, Part V Libraries: 从这里开始是各种库, 有预定义的各种命令.
page 240;
/tikz/below=<specification>
/tikz/left=<specification>
/tikz/right=<specification>
/tikz/below left=<specification>
/tikz/below right=<specification>
/tikz/above left=<specification>
/tikz/above left=<specification>
类似above
,但是<shifting parti>
的指定更加复杂.
- 当
<shifting part>
形式为<number or dimension> and <number or dimension>
的时候(注意中间有个and
), 先向左移动, 再向右移动(通常这令人满意, 除非你使用了x
andy
选项, 修改了xy
--坐标系的单位矢量. ) - 当
<shifting part>
形式为<number or dimension>
时, 也就是只给出一个参数, 向对角线方向(135度方向)移动$\frac{1}{2}\sqrt{2}cm$. 按照数学的说法, 就是按照$l_{2}-norm$理解, 相当于极坐标中的半径. 而<number or dimension> and <number or dimension>
是按照$l_{1}-norm$理解.
page 260; 17.13 Referencing Nodes Outside the Current Picture
可以在图片A
中引用图片B
中的node
( 但不是很trivial) .
这意味着你可以创建图片和一个节点
, 稍后你可以从其他位置画一条线(edge
)到这个节点
.
要引用不同图片中的节点, 请按以下步骤操作.
- 你需要在所有包含
目标节点
的图片上添加remember picture
选项, 同时也要在所有包含起始节点
的图片上添加remember picture
选项. - 您需要为路径或整个图片添加
overlay
选项, 这些图片包含对域外节点
的引用. (这个选项可以关闭bounding box
的计算) . - 你需要使用一个支持
remember picture
的驱动程序
,pdfLaTeX
是支持的, 并且你需要运行TeX
两次. 关于幕后操作的更多细节, 见第107.3.2节. 让我们来看看这些选项的效果.
/tikz/remember picture=<boolean> 无默认, 初始值为 false
这个选项告诉TikZ
, 它应该尝试记住当前图片
在页面上的位置. 这种尝试可能会失败, 这取决于使用的是哪种后端驱动程序.
另外, 即使记忆成功, 这个位置可能也只在第二次运行TeX
程序才能用. 如果可以记忆的话, 你可以考虑
\tikzset{every picture/.append style={remember picture}}
来使TikZ
记住所有图片. 这将在.aux
文件中为每张图片添加一行记录--通常不会很多.
然后, 你就不必担心记忆图片的问题了.
/tikz/overlay=<boolean> 默认为 true
这个选项主要是为了在引用其他图片中的节点时使用, 但你也可以在其他情况下使用它在其他情况下使用.
这个选项的作用是, 在计算当前图片的边界框
时, 不会考虑到当前scope
范围内的所有对象.
你需要在所有包含域外节点
引用的路径( 或者至少是路径的所有部分) 指定这个选项.
否则, TikZ
会试图使当前的图片足够大, 以涵盖其他图片中的节点
. 然而, 在TeX
的第二次运行中, 这将创建一个更大的图片, 导致图片越来越大.
除非你知道自己在做什么, 否则我建议在所有包含域外引用
的图片上指定overlay
选项.
现在让我们看几个例子. 这些例子只有在用支持remember picture
的驱动程序处理文档时才有效.
在当前文本中, 我们放置两张图片, 包含名为n1
和n2
的节点,
\tikz[remember picture] \node[circle,fill=red!50] (n1) {};
\tikz[remember picture] \node[fill=blue!50] (n2) {};
为了连接这些节点, 我们使用overlay
和 remember picture
选项创建另一张图片.
\begin{tikzpicture}[remember picture,overlay]
\draw[->,very thick] (n1) -- (n2);
\end{tikzpicture}
注意, 最后一张图片似乎是空的. 实际上它的大小为零, 并且包含在它边界之外的箭头.
最后一个例子, 我们将另一张图片中的节点
连接到前两个节点
.
在这里, 我们只给连线提供了overlay
选项, 我们不希望把这条线算作图片的一部分.
\begin{tikzpicture}[remember picture]
\node (c) [circle,draw] {Big circle};
\draw[overlay,->,very thick,red,opacity=.5] (c) to [bend left] (n1) (n1) -| (n2);
\end{tikzpicture}
有一个特殊的节点叫做current page
, 可以用来访问当前页.
它是一个长方形的节点, 其south west
锚点是页面的左下角
, north east
锚点是页面的右上角
.
这个节点在内部是以特殊的方式处理的, 你可以引用它, 就像它已经被记忆过
一样.
因此, 通过给图片增加remember picture
和overlay
选项, 你可以在页面上绝对定位
节点.
第一个例子将文本放在当前页面的左下角.
\begin{tikzpicture}[remember picture]
\node[xshift=1cm,yshift=1cm] at (current page.south west)
[text width=7cm, fill=red!20,rounded corners,above right]
{
This is an absolutely positioned text in the lower left corner. No shipout-hackery is used.
}
\end{tikzpicture}
下一个例子在页面中间添加圆圈.
\begin{tikzpicture}[remember picture]
\draw [line width=1mm,opacity=.25]
(current page.center) circle (3cm);
\end{tikzpicture}
最后一个例子在页面上方叠加文字( 取决于例子的位置, 也可能出现在下一页).
\begin{tikzpicture}[remember picture,overlay]
\node [rotate=60,scale=10,text opacity=0.2] at (current page.center) {Example};
\end{tikzpicture}
给节点提供的所有选项只影响本节点自己. 虽然这在大多数情况下是件好事, 但你有时可能想让选项在 以后
产生影响.
反过来说, 你有时可能会注意到一些选项只应该在后期
被添加到节点上. 于此,可以使用下面这个版本的node
路径命令:
\path … node also[<late options>](<name>) …;
请注意, <name>
是强制性的, 不能在这里给出节点文本. 另外, 选项和节点标签的顺序必须如上.
节点<name>
必须已经存在. <late options>
是在局域scope
中执行的. 这些选项中的大多数不会有任何影响, 因为你不能改变节点的外观.
也就是说, 你不能用late
选项把一个红色节点变成绿色节点.
然而, 在<late options>
选项里面给出append after command
和prefix after command
选项 (直接或间接地)确实能达到预期的效果.
给定的路径被执行, \tikzlastnode
被设置为 determined node.
所有这些的净效果是, 例如, 你可以提供label
选项, 为已被创建的节点添加标签:
\begin{tikzpicture}
\node [draw,circle] (a) {Hello};
\node also [label=above:world] (a);
\end{tikzpicture}
正如 Section 14 所解释的, 你可以使用选项append after command
和prefix after command
在节点后添加路径. 下面的宏可能很有用.
\tikzlastnode
; 展开为路径上的最后一个节点. 你也可以用下面的选项
来代替node also
语法.
/tikz/late options=<options> (无默认值)
这个选项可以在路径
上给出( 但不能作为节点
命令的参数) , 其效果与node alos
命令相同.
在<options>
中, 你应该使用name
选项来指定你希望添加late option
的节点
\begin{tikzpicture}
\node [draw,circle] (a) {Hello};
\path [late options={name=a, label=above:world}];
\end{tikzpicture}
page 353: 23 Transparency
常用透明度选项:
/tikz/draw opacity=<value>
/tikz/fill opacity=<value>
<value>
除了数字取值[0,1]
之外, 还可以下列预设:
/tikz/transparent
/tikz/ultra nearly transparent
/tikz/very nearly transparent
/tikz/nearly transparent
/tikz/semitransparent
/tikz/nearly opaque
/tikz/very nearly opaque
/tikz/ultra nearly opaque
/tikz/opaque
p416 ; 27 Introduction to Algorithmic Graph Drawing
算法图形绘制(Algorithmic graph drawing)( 或以下简称为图形绘制) 是以算法计算图形节点在页面上的位置的过程, 以便使图形 看起来漂亮
.
它的想法是, 作为人类用户( 或者你碰巧是一台机器, 并且碰巧在阅读这篇文档) , 只需要指定哪些节点, 以及哪些连线存在于图中.
此外, 你可以添加一些 提示
, 比如 这个节点应该在中心附近
或 这条边很重要
.
你并不指定节点和边的确切位置, 这是留给图形绘制算法的事情(graph drawing algorithm). 该算法将你对图形的描述作为输入, 然后决定节点应该放在页面何处.
自然, 画图是一门(黑色的)艺术. 确切地说, 没有 完美
的方法来绘制图形.
与纯粹用TEX
实现的pgf
和TikZ
的其他部分不同, 图形绘制算法太过复杂, 无法直接用TEX
实现.
与pgf
和TikZ
的其他部分不同的是, 图形绘制算法过于复杂, 无法直接在TEX
中实现.
相反, 编程语言Lua
被用于 图形绘制库所使用的编程语言--这种编程语言已被集成到最近的TEX
版本中. 这意味着:
- 作为图形绘制引擎的用户, 你可以在你的文档中以通常的方式运行
TEX
, 而不需要调用外部程序
. - 非常容易为
Tikz
实现新的会图算法, 因为可以使用Lua
, 而不需要TeX
的编程知识.
通常, 图形绘制引擎的 用户
只需在他们的图片上添加一个选项
, 即可调用图形绘制算法.
这是一个典型的例子, 其中layered layout
选项告诉TikZ
图应该使用所谓的layered graph drawing algorithm
来绘制(来摊开
)(这些都将在后面解释). )
在所有的例子中, 节点
的位置, 只有当所有的节点
都被创建, 并指定了边
之后才被计算.
例如, 在最后一个例子中, 如果没有选项 spring electrical layout
, 所有的节点都会被放在彼此的上面.
尽管下面几节介绍的图形绘制
系统是作为pgf
的一部分开发的, 但它可以独立于pgf
和TikZ
使用.
它可以被任意的程序使用, 只要后者可以运行Lua
. 为了实现这一点, 图形绘制系统由三层组成.
-
在
底部
我们有algorithmic layer
. 这一层是用Lua
写的, 包含了所有的图形绘制算法. 有趣的是,选项
也必须在这一层声明, 所以一个算法连同它使用的所有选项
可以而且必须完全在这一层指定. 如果你打算实现一个新的图形绘制算法, 你将只对这一层的功能感兴趣. 算法通过一个定义明确的接口与图形绘制系统交流
, 该接口封装在InterfaceToAlgorithms
类中. -
在
顶部
我们有显示层
. 这个层实际上不是图形绘制系统
的一部分. 相反, 它是一个显示
图形的软件,TikZ
只是这种软件的一个例子. 另一个例子是一个图形编辑器
, 它使用图形绘制系统
来布置图形它的子图. 还有比如命令行
工具, 用于绘制文件
中描述的图形. 最后, 你也可能希望使用图形绘制系统作为子程序来渲染在更大的程序中产生的图形.
由于显示层的不同实现可能是相当异质的, 所有的显示层必须通过一个特殊的接口与图形绘制系统
进行通信, 该接口被封装在类InterfaceToDisplay
中.
这个类的主要工作是提供一组方法, 用于指定一个图形有某些节点
和边
, 并且为它们设置某些选项.
然而, 这个接口也允许你查询
所有被算法声明的选项, 包括它们的文档.
这样一来, 编辑器或命令行工具可以列出所有图形绘制算法
, 以及它们应该如何配置.
算法层
和显示层
通过绑定层
"绑定" 在一起. 关于待画图形的大部分bookkeeping
(记录)工作是由图形绘制系统
完成的, 与使用的算法
和显示层
无关. 但有些事情仍然是针对具体显示层
的. 例如, 一些算法可能会创建新的节点
, 而这些算法
可能需要知道这些节点有多大. 为此, 在算法
运行期间,显示层
必须被查询
, 而实现这一回调
(callback)是绑定层
的工作. 通常情况下,绑定层
实现了从图形绘制系统
到显示层
的后向
通信. 而显示层
的接口类只提供了从显示层
调用的函数, 但它们不会talk back
.
所有与图形绘制
有关的文件都位于generic/pgf
的graphdrawing
子目录下.
\usetikzlibrary{graphdrawing} % LATEX and plainTEX
\usetikzlibrary[graphdrawing] % ConTEXt
这个包提供了自动绘制图形的功能. 它要求文件使用LuaTeX
排版. 这个包应该在LuaTEX 0.54
或更高版本中使用.
当你加载graphdrawing
库时, 图形绘制引擎被初始化. 这个库提供了图形绘制的基本框架, 包括本节中描述的所有选项
和键
.
然而这个库并没有加载任何实际的图形绘制算法. 为此, 你需要使用以下命令, 它是由graphdrawing
库定义的.
\usegdlibrary{<list of libraries>}
该命令用于加载特殊的图形绘制库(命令名称中的gd
代表 graph drawing
).
<list of libraries>
是一个用逗号
分隔的列表, 其中包括用Lua
编程语言编写的库. (这就是为什么需要一个特殊的命令).
详细来说, 这个命令做了以下工作. 对于<list of libraries>
中的每一个<name>
:
- 检查
LuaTEX
是否可以对库文件pgf.gd.<name>.library
调用require
.LuaTEX
的文件搜索机制将以通常的方式搜索texmf-trees
, 文件名中的点
被转换成目录斜线
. - 如果上述方法失败, 尝试
require
字符串pgf.gd.<name>
. - 如果失败, 尝试
require
字符串<name>.library
. - 如果失败, 尝试要求字符串
<name>
. 如果这也失败, 打印一条错误信息.
上述情况的纯粹作用如下.
图形绘制算法
的作者可以将多种算法捆绑在一起, 通过创建一个 ...xyz/library.lua
文件, 该文件内部对所有包含声明的文件调用require
.
另一方面, 如果一个图形绘制算法
完全适合存放在一个文件中, 也可以直接使用 \usegdlibrary
读取.
\usetikzlibrary{graphdrawing}
\usegdlibrary{trees,force}
不同的图形绘制库在下面的第30
至35
节中有记录.
注意, 除了图形绘制库之外, 你可能还希望加载普通的TikZ
库graphs
. 它提供了强大的graph
path 命令, 以其易于使用的语法来指定图形.
但你可以独立于graphs
使用图形绘制引擎
, 例如结合child
或edge
语法使用. 下面是典型的设置:
\usetikzlibrary{graphs, graphdrawing}
\usegdlibrary{trees, layered}
设置好之后, 你必须指定图形绘制引擎
使用哪种布局算法, 应用到哪个scope
中的节点.
通常情况下, 你只需在graph
path 操作中添加一个以... layout
结尾的选项
即可, 然后让图形绘制完成它的魔法
\usetikzlibrary {graphs,graphdrawing} \usegdlibrary {layered}
\tikz [rounded corners]
\graph [layered layout, sibling distance=8mm, level distance=8mm]
{
a -> { b, c -> { d, e }
} -> f -> a};
每当你使用这样的布局选项时, 你可以:
- 以通常的方式创建
节点
. 节点将被完全创建, 但会被藏在一个内部表格中. 这意味着可以使用所有TikZ
中对节点的选项. 你还可以为一个节点命名并在以后引用它. - 使用
graph
命令的语法(使用--
,<-
,->
或<->
)创建edges
, 或者使用edge
命令, 或使用child
命令. 然而, 这些边不会立即被创建. 相反, 基础层的命令\pgfgdedge
将被调用, 它存储了所有关于边缘的信息
.edges
的实际绘制只有在所有节点
都被定位后才会发生. - 大多数可以传递给
edge
的键
都会像预期的那样工作. 特别是, 你可以使用通常的node
语法将标签添加到边上
. lable
和pin
选项可以以通常的方式用于图形绘制 scope
内的节点. 只是,lable
和pin
在节点的定位中不会起任何作用, 它们是在节点最终被定位后加入.- 同样, 可以使用通常的
隐式定位语法
, 将节点
放置在edge
上.
下面是一些不会工作的东西.
- 只有使用
graph
语法,edge
命令或child
命令创建的edges
才能正确地将它们的连接信息传递给基础层
. 当你在图形绘制scope
内写下\draw (a)--(b);
时, 其中a
和b
是在该scope
内创建的节点, 你会得到一个错误消息/结果会看起来不对. 原因是通常的--
不会被图形绘制引擎捕捉到
, 因此,--
试图立即连接两个不存在的节点(除了在一些内部表中). edges
的选项被执行两次: 一次是当edge
被\pgfgdedge
命令 "检查 "时(使用一些魔法来防止副作用), 然后在edge
被实际创建时再执行一次. 幸运的是, 在几乎所有的情况下, 这不会是一个问题;但是如果你在你的edge
选项里施展了邪恶的魔法, 你必须祈求佛祖保佑了. (不要整烂活, 顺便说一下) 如果你对细节
感兴趣, 请看第29节.
p975. key
就是tikz
中的各种关键字, 它们是通过包pgfkeys
管理的. \usepackage{pgfkeys}
.
key
的例子: /tikz/coordinate system/x
, 或者只用写/x
. 这种写法类似于Unix
上的文件路径. 可以使用绝对路径, 也可以使用相对路径. tikz
的key
名称经常包含空格.
调用key
使用\pgfkeys
命令. pgfkeys
接受key=value
形式的参数. 例如:
\pgfkeys{/my key=hallo, /your keys=something\strange, others=something else}
可以在key
中存储一些code
, 通常用handler
来管理key
的内容. 例如:
\pgfkeys{/my key/.code=The value is '#1'.}
\pgfkeys{/my key=hi!}
有许多handler
可以用来定义key
. 例如, 我们可以定义一个具有多个参数的key
:
\pgfkeys{/my key/.code 2 args=The values are '#1' and '#2'.}
\pgfkeys{/my key={a1}{a2}}
常用handler
有:
.default
:提供默认值./.value required
:必须指定参数./.value forbidden
:不能指定参数.
tikz
的所有key
都以/tikz
开头. 然而不必每次都显式加上这个前缀, 可以使用/.cd
来声明默认目录.
\pgfkeys{/tikz/.cd,line width=1cm, linecap=round}
当处理一个key
时, 除了直接执行某些代码, 也可以递归调用另一些keys
, 这种key
被称为styles
. styles
本质上就是key
的列表. 例如:
\pgfkeys{/a/.code=(a:#1)}
\pgfkeys{/b/.code=(b:#1)}
\pgfkeys{/my style/.style={/a=foo,/b=bar,/a=#1}}
\pgfkeys{/my style=wow}
.styles
也可以带有参数#1
, 如同普通的.code
.
p975, key
的组织方式类似Unix
. /a/b.../x
中, 前面的/a/b.../
是路径
, 后面的x
是名称
.
pgfkeys
包中有一些内部命令, 如\pgfkeyssetvalue
, \pgfkeyslet
等等. 但是通常用户不需要直接调用这些命令.
简要提一下\def
, \let
,\edef
三个命令: What is the difference between \let and \def
\let
相当于直接赋值, 右边的式子计算之后赋给左边. \def
命令相当于mma中的SetDelay
即:=
, 会在被调用时重新计算.
\edef
是expand def
的缩写, 也就是赋值之前右边的式子会被展开.
handler
相当于key
的方法, 或者构造函数之类的.
p984, 常用的 key handler
:
<key>/.cd
: 设置默认路径为key
.<key>/.is family
: 当使用key
时, 当前路径被设置为key
,效果同<key>/.cd
.<key>/.default=<值>
:设置key
的默认值. 例如\pgfkeys{/width/.default=1cm}
<key>/.value required
: 表明必须赋值.<key>/.value forbidden
: 表明禁止赋值.<key>/.code=<代码>
: 添加代码, 可以有一个参数#1
<key>/.code 2 args=<代码>
:表示有两个参数{#1}{#2}
, 如果第二个未给出, 将会是空字符. 如果传入first
, 第一个参数将是f
, 第二个将是irst
, 所以需要用{}
包裹起来.<key>/.code n args={<m>}{<代码>}
:传入m
个参数{#1}{#2}{#3}...
,m
为0~9
, 不能多也不能少, 空格也可以作为参数.<key>/.code args={<参数模式>}{<代码>}
:可以指定任意的参数模式, 比如(#1/#2)
,调用对应的写成(first/second)
, 空格将被去掉.<key>/.add code={<前缀代码>}{<后缀代码>}
: 将代码添加到已经存在的key
.<key>/.prefix code=<前缀代码>
: 类似.add code
, 但只添加前缀.<key>/.append code=<后缀代码>
: 类似.add code
, 但只添加后缀.
其中 .code 2 args
和.code args
的区别见下面的例子:
\pgfkeys{/page size/.code 2 args={\paperheight=#2\paperwidth=#1}}
\pgfkeys{/page size={30cm}{20cm}}
% 同样的定义, 使用 .code args
\pgfkeys{/page size/.code args={#1 and #2}{\paperheight=#2\paperwidth=#1}}
\pgfkeys{/page size=30cm and 20cm}
.style
是key
的列表, 它的handler
和key
基本相同, 只需要作替换.code
->.style