TikZ 是在 LaTeX 中直接用代码绘制矢量图的标准系统。你把坐标、线、圆、箭头和节点写在与正文相同的源文件中,图形就会以与正文相同的字体和质量排版完成。不必在外部绘图软件之间来回切换;图形会成为文档中可复现的一部分——这就是本页的主题。
PGF 与 TikZ
先整理名称。底层是 PGF(Portable Graphics Format),这是实际绘制线条的 低层图形引擎,同时屏蔽驱动差异(PDF 与 DVI 等)。直接书写原始 PGF 很费力。因此,TikZ 是覆盖在 PGF 之上的友好前端(宏层),让绘图更容易书写。两者都由 Till Tantau 创建。
TikZ 这个名字是德语 “TikZ ist kein Zeichenprogramm”(“TikZ 不是绘图程序”)的递归缩写,采用 GNU 风格的自指命名。读音没有官方固定形式,你可能会听到 /tiks/、/tikts/ 或 /tik-zee/。实际使用中,人们常把 “PGF/TikZ” 作为一个整体来说,而我们实际书写的几乎总是 TikZ 这一层。
入门很简单:只需在导言区写 \usepackage{tikz},PGF 也会随之加载。它可直接用于 pdfLaTeX、LuaLaTeX 和 XeLaTeX。只有像 pLaTeX 或 upLaTeX 那样经过 DVI 时,才需要把驱动(通常是 dvipdfmx)指定为文档类选项。
\documentclass{article} % pLaTeX なら \documentclass[dvipdfmx]{jsarticle}
\usepackage{tikz}
\begin{document}
We are working on
\begin{tikzpicture}
\draw (-1.5,0) -- (1.5,0);
\draw (0,-1.5) -- (0,1.5);
\end{tikzpicture}.
\end{document}这会先排出文字 “We are working on”,然后在同一行中绘制一个穿过原点的小十字(水平线和垂直线),最后加上句点。图形融入文字行的感觉,正是 TikZ 的味道。
tikzpicture 环境
所有图形都绘制在 tikzpicture 环境(\begin{tikzpicture} … \end{tikzpicture})中。它就是容纳一幅图的“画布”,里面依次写绘图命令。环境名后面的方括号中可以写作用于整幅图的选项(例如 [scale=2] 表示放大 2 倍,[thick] 表示整体使用较粗线条)。
对于一行内的小图,不一定要打开环境:可以使用 \tikz{...},或者只有一个命令时使用 \tikz \draw ...; 这种行内形式。无论使用哪种形式,有一条规则绝不能忘:每条绘图命令都以分号 ; 结束。分号表示“这条路径到此为止”,漏写就会出错,这是初学者最常踩的点。
% 行内(インライン)
\tikz \draw (0,0) -- (1.5,0);
% 環境(複数のコマンド)
\begin{tikzpicture}
\draw (-1.5,0) -- (1.5,0) -- (0,-1.5) -- (0,1.5);
\end{tikzpicture}路径模型 — 坐标与路径操作
TikZ 绘图围绕 路径(path)展开。路径描述“从一个点到另一个点怎样前进”,而命令名决定这条路径如何显示。\draw 用线描画路径,\fill 填充闭合路径内部,\filldraw 先填充再描边,\path 只定义路径而不绘制任何内容(常用于放置之后要引用的坐标或节点)。
指定点(坐标)有三种方式。直角坐标 (x,y) 默认单位为厘米,所以 (1,2) 表示向右 1 cm、向上 2 cm;也可以像 (1cm,2pt) 这样显式给出单位。极坐标 (angle:radius) 表示“沿这个方向走这么远”,如 (30:1cm)。如果给点命名(命名坐标),之后可用名称调用。也可以相对移动:++(1,0) 从当前位置向右走 1 cm 并更新当前位置,而 +(1,0) 只表示相对起点的位置,不更新当前位置。
路径操作决定路线如何前进。-- 从前一个点到下一个点画 直线(像 (a) -- (b) 这样串起来)。rectangle 由两个对角点生成矩形,circle 以中心画圆,ellipse 画椭圆,arc 画圆弧,grid 画网格线。曲线用 .. controls ..(Bézier 曲线)或后面会看到的 to[bend] 绘制。要闭合图形,在末尾加 -- cycle 回到起点。
现代写法是把形状参数作为方括号 [...] 中的键值对传入。圆写作 circle [radius=10pt],椭圆写作 ellipse [x radius=20pt, y radius=10pt],圆弧写作 arc [start angle=0, end angle=30, radius=3mm](从 0° 到 30°、半径 3 mm)。对于 grid,用 [step=.5cm] 设置间距。下例先画浅色网格,再在原点画半径 1 cm 的圆,以及从原点到 (1,1) 的直线。
\begin{tikzpicture}
\draw[step=.5cm, gray, very thin] (-1.4,-1.4) grid (1.4,1.4);
\draw (0,0) circle [radius=1cm];
\draw (0,0) -- (1,1);
\fill[blue!20] (0,0) rectangle (0.5,0.5);
\end{tikzpicture}这幅图先从 (-1.4,-1.4) 到 (1.4,1.4) 绘制 0.5 cm 间隔的浅灰网格,然后叠加以原点为中心的圆、从原点到右上方 (1,1) 的斜线,以及原点处一个 0.5 cm 见方、填充浅蓝色的小正方形。blue!20 表示“20% 蓝”,也就是蓝色与白色混合后的浅蓝。
节点 — 放置文字与形状
节点(node)是在指定坐标上 放置文字或形状 的机制,是给图加标签的主力。基本形式是 \node[options] (name) at (coordinate) {contents};。选项可以包括 draw(描边框)、circle 或 rectangle(形状)、fill=blue!20(填充)等。圆括号中的 name 成为该节点的句柄,之后可用 (name) 或 (name.north) 等引用其位置。
实际使用中最常见的模式是:先放置带名称的节点,再用线连接这些名称。因为连接的是节点名而不是原始坐标,所以即使调整布局,连线也会自动跟随。
\begin{tikzpicture}
\node (a) at (0,0) [draw, circle, fill=blue!20] {A};
\node (b) at (2.5,0) [draw, circle, fill=blue!20] {B};
\draw[->] (a) -- (b);
\end{tikzpicture}这会绘制两个浅蓝色圆形节点,分别标为 “A” 和 “B”,相距 2.5 cm,并从 A 到 B 画一条带箭头的直线。线条会自然停在各节点边界处,不会插入圆内。
节点也可以放在路径 途中。写 \draw (a) -- (b) node[midway] {label}; 会把标签放在从 a 到 b 的线段 中点(midway)。加上 above 或 below 可把它移到线的上方或下方。这是给连接线添加说明的标准写法。
选项与样式
线条外观可用方括号中的 选项 细致控制。常用项包括线宽 thin / thick / very thick,颜色 red 或 blue!50,虚线 dashed、点线 dotted,圆角 rounded corners,以及箭头。箭头为 ->(末端箭头)、<-(起点箭头)、<->(两端箭头)。实际上 TikZ 的设计很务实:任何包含 - 的未知选项都会被解释为箭头规格。
| 选项 | 含义 |
|---|---|
thick / very thick | 加粗线条(直到 ultra thick) |
red, fill=blue!50 | 描边或填充颜色(!n 设置浓度) |
dashed / dotted | 虚线或点线 |
rounded corners | 将路径的拐角变圆 |
->, <-, <-> | 末端、起点或两端的箭头 |
scale=2 | 将该图(或路径)放大 2 倍 |
如果同样的装饰要反复书写,惯用做法是 把它命名为样式并复用。可在导言区用 \tikzset{name/.style={...}} 定义,也可在 tikzpicture 选项中现场定义。例如下面定义了一个 help lines 样式,并将其应用到网格。
\tikzset{help lines/.style={color=blue!50, very thin}}
\begin{tikzpicture}
\draw[help lines] (0,0) grid (3,2);
\draw[thick, red, ->, rounded corners] (0,0) -- (1,2) -- (3,2);
\end{tikzpicture}这会从 (0,0) 到 (3,2) 绘制浅蓝网格,再画一条从原点到 (1,2)、再到 (3,2) 的红色粗折线,折角为圆角,末端有箭头。因为网格使用了样式,只需把 very thin 改成 thin,就能一次性改变整个网格的外观。
库 — 加载需要的功能
TikZ 核心有意保持较小,专门功能被拆分到 库 中。可在导言区用 \usetikzlibrary{...} 只加载需要的库(多个库用逗号分隔)。常用库如下:
arrows.meta— 丰富且可调的箭头集合(-{Stealth}、-{Latex}等)。旧的arrows库已不推荐;现在使用这个。positioning— 相对放置节点,可写right=of a或below=1cm of b(“在该节点右侧”、“在其下方 1 cm”)。calc— 坐标计算:($(a)+(1,0)$)表示 “a 右侧 1 cm”,($(a)!0.5!(b)$)表示 “a 与 b 的中点”。shapes— 除圆形和矩形外的大量节点形状(菱形、星形、标注框等)。还细分为shapes.geometric等。decorations— 将路径装饰成波浪、锯齿、括号等(如decorations.pathmorphing)。patterns— 用剖线、点等图案填充。fit— 自动生成包围多个节点的盒子。backgrounds— 在图片后方的背景层绘制边框或底色。matrix— 将节点排列成网格(矩阵);graphdrawing可自动布局(需要 LuaTeX)。
下例是一个结合 arrows.meta 和 positioning 的小流程图。只有第一个节点给出坐标,其余节点通过“右侧”“下方”等相对指定排列,并用 Stealth 样式箭头连接。
\usepackage{tikz}
\usetikzlibrary{arrows.meta, positioning}
\begin{tikzpicture}[node distance=1cm, every node/.style={draw, rounded corners}]
\node (start) {Start};
\node (proc) [right=of start] {Process};
\node (end) [right=of proc] {End};
\draw[-{Stealth}] (start) -- (proc);
\draw[-{Stealth}] (proc) -- (end);
\end{tikzpicture}这会生成一个从左到右的流程图:三个带圆角边框的节点 “Start”、“Process”、“End” 间隔 1 cm 排列,并用尖锐的 Stealth 箭头依次连接。关键是 every node/.style,它一次性为所有节点指定共同外观。
编译成本与 externalize
TikZ 图形由 LaTeX 逐个元素计算并绘制,因此复杂图形或图形很多的文档会让 编译明显变慢。尤其是图表和密集网格通常较重。
标准对策是 externalize 库。加载 \usetikzlibrary{external} 并声明 \tikzexternalize 后,每个 tikzpicture 只会单独编译一次为 PDF 并 缓存。之后如果图的内容没有变化,TikZ 会跳过计算,直接插入已生成的 PDF。第一次运行较慢,但后续编辑循环会快很多(修改图形后会自动重新生成)。另一种做法是把大图拆到单独文件中,用 standalone 类单独编译。