1. 概述
在本教程中,我们将学习如何使用 LaTeX 绘制图形。
我们会先介绍几个常用的 LaTeX 图形绘制包,并说明它们各自的优势。
接着,我们会通过具体示例展示如何使用这些包来绘制图形,并讨论其变体。
最后,你将能够熟练地在 LaTeX 文档中实现图形绘制。
2. 图形的基本概念回顾
2.1. 图形的组成及其表示方式
一个图 G(V, E) 包含一组顶点集合 V 和一组边集合 E。边可以是有向的或无向的,通常连接两个顶点,但这两个顶点不一定是不同的。对于超图(Hypergraph),边可以连接多个顶点,但本文不涉及这部分内容。
标准的顶点表示通常是一个圆圈:
如果顶点有标签,通常会将其写在圆圈内部,如上面示例中的数字 1 所示。我们也可以通过合理布局多个顶点,使它们不会重叠地分布在图中:
边的标准表示是:无向边用直线表示,有向边用箭头表示:
2.2. 图形的典型表示方式
因此,一个图形图像通常由以下两部分组成:
- 一组分布在空白背景上的圆圈(顶点)
- 一组连接这些圆圈的线或箭头(边)
如果是加权图(Weighted Graph),我们还可以在边上标注权重值:
此外,如果图中包含自环(Loop),我们也可以用从顶点出发再回到该顶点的边来表示:
这些就是我们绘制任意复杂度的图所需的基本元素。接下来,我们将学习用于绘制图的 LaTeX 包,并通过代码示例来实现这些图形。
2.3. 图形的其他表示方式
不过,图形的图像表示并不是唯一直观的表示方法。还有其他一些常见表示方式,例如:
- 边列表(Edge List)
- 邻接表(Adjacency List)
- 邻接矩阵(Adjacency Matrix)
在某些情况下,这些形式可能比图形图像更容易理解。例如,一个包含 26 个顶点 V = {A, B, ..., X, Y, Z}
、仅有两个边 E = {(X, Y), (X, Z)}
的有向图,用形式化表示非常简洁:
但如果用图形方式完整表示,会占用大量空间,而且信息密度低。当图中顶点或边的数量较多时,图像表示往往难以传达结构信息。
例如,互联网节点图的图形表示虽然美观,但对人类阅读者来说意义不大。因此,当图的规模较大时,应避免使用图像表示,而应优先使用邻接矩阵、边列表等更紧凑的形式。
3. TikZ
接下来我们介绍可用于在 LaTeX 中绘制图的包。最常用的图形绘制包是 TikZ,它基于 PGF 构建,简化了语法,功能强大。
TikZ 提供了多个库来支持不同任务,例如:
- 绘制思维导图(Mindmaps)
- 绘制实体关系图(ER Diagrams)
- 绘制逻辑电路图(Logic Circuits)
对于我们来说,最相关的是它的 graphdrawing
库,可以用于自动绘制图结构。
我们将以 TikZ 为主,通过代码示例来展示如何绘制图。
3.1. 基本图形与节点
TikZ 的图形绘制是在 tikzpicture
环境中完成的。最简单的图是一个顶点,例如:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[main/.style = {draw, circle}]
\node[main] (1) {$x_1$};
\end{tikzpicture}
\end{document}
渲染结果如下:
其中 main
是我们定义的样式,表示节点为圆形。
主要命令是 \node
,其语法为:
\node[参数] (节点ID) {节点标签};
我们可以多次使用这个命令来添加更多节点:
\node[main] (2) [above right of=1] {$x_2$};
\node[main] (3) [below right of=1] {$x_3$};
\node[main] (4) [above right of=3] {$x_4$};
\node[main] (5) [above right of=4] {$x_5$};
\node[main] (6) [below right of=4] {$x_6$};
渲染结果如下:
注意:[above right of=1]
这样的参数表示相对位置。使用相对位置的好处是,我们可以只移动一个锚点节点,就能调整整个图的布局。
3.2. 添加边
我们可以使用 \draw
命令来添加边:
\draw[参数] (起点) -- (终点);
例如,添加无向边:
\draw (2) -- (4);
渲染结果如下:
添加有向边时,只需加上 ->
参数:
\draw[->] (1) -- (2);
渲染结果如下:
3.3. 调整边宽与节点间距
默认边线较细,难以区分有向与无向边。我们可以通过设置 thick
参数增强可读性:
\begin{tikzpicture}[thick, main/.style = {draw, circle}]
渲染结果如下:
如果节点太密集,可以设置 node distance
调整间距:
\begin{tikzpicture}[node distance={15mm}, thick, main/.style = {draw, circle}]
渲染结果如下:
3.4. 复杂边的绘制
有些边如果直接连接会与其他边或节点交叉。例如:
\draw (1) -- (5);
渲染结果如下:
我们希望边绕过节点 2,从外部连接。可以使用 to
命令并指定角度与松紧度:
\draw (1) to [out=135,in=90,looseness=1.5] (5);
渲染结果如下:
3.5. 自环边
绘制自环边的方式类似:
\draw (1) to [out=180,in=270,looseness=5] (1);
渲染结果如下:
3.6. 加权边
对于加权图,可以在边中插入标签:
\draw[->] (6) -- node[midway, above right, sloped, pos=1] {+1} (4);
渲染结果如下:
其中 node
表示插入一个不可见节点,midway
表示在边中间,above right
表示偏移方向,sloped
表示标签与边垂直,pos
控制偏移位置。
3.7. 完整图形示例
将以上所有命令组合起来,即可绘制一个完整的图:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[node distance={15mm}, thick, main/.style = {draw, circle}]
\node[main] (1) {$x_1$};
\node[main] (2) [above right of=1] {$x_2$};
\node[main] (3) [below right of=1] {$x_3$};
\node[main] (4) [above right of=3] {$x_4$};
\node[main] (5) [above right of=4] {$x_5$};
\node[main] (6) [below right of=4] {$x_6$};
\draw[->] (1) -- (2);
\draw[->] (1) -- (3);
\draw (1) to [out=135,in=90,looseness=1.5] (5);
\draw (1) to [out=180,in=270,looseness=5] (1);
\draw (2) -- (4);
\draw (3) -- (4);
\draw (5) -- (4);
\draw[->] (5) to [out=315, in=315, looseness=2.5] (3);
\draw[->] (6) -- node[midway, above right, sloped, pos=1] {+1} (4);
\end{tikzpicture}
\end{document}
渲染结果如下:
4. Neuralnetwork
另一个用于生成图的 LaTeX 包是 neuralnetwork
,特别适合绘制神经网络架构,尤其是前馈神经网络(Feedforward Neural Networks)。
它的优势在于快速构建图结构,只需几行代码即可完成一个完整网络的绘制。但缺点是自定义能力较弱。
4.1. 包的基本使用
在 neuralnetwork
包中,图结构是在 neuralnetwork
环境中定义的:
\begin{neuralnetwork}
...
\end{neuralnetwork}
我们可以使用以下命令添加层:
\inputlayer
:输入层\hiddenlayer
:隐藏层\outputlayer
:输出层
语法如下:
\inputlayer[count=3, bias=false]{}
count
:节点数量bias
:是否包含偏置项text
:节点标签格式
4.2. 绘制一个神经网络
例如,绘制一个包含 3 个输入节点、1 个隐藏层(2 个节点)、1 个输出节点的神经网络:
\documentclass{article}
\usepackage{neuralnetwork}
\begin{document}
\begin{neuralnetwork}
\inputlayer[count=3, bias=false]{}
\hiddenlayer[count=2]{}
\outputlayer[count=1]{}
\end{neuralnetwork}
\end{document}
渲染结果如下:
4.3. 添加边与标签
使用 \linklayers
命令连接相邻层:
\inputlayer[count=3, bias=false]{} \linklayers
\hiddenlayer[count=2]{} \linklayers
\outputlayer[count=1]{}
渲染结果如下:
我们可以通过定义命令来添加节点标签:
\newcommand{\x}[2]{$x_#2$}
\inputlayer[count=3, bias=false, text=\x]{}
渲染结果如下:
同样可以为隐藏层和输出层添加标签:
\newcommand{\h}[2]{$h_#2$}
\newcommand{\y}[2]{$y_#2$}
\hiddenlayer[count=2, text=\h]{} \linklayers
\outputlayer[count=1, text=\y]{} \linklayers
渲染结果如下:
4.4. 添加权重
可以定义一个命令来显示权重:
\newcommand{\w}[4] {$w_{#2,#4}$}
\setdefaultlinklabel{\w}
渲染结果如下:
如果某些权重未显示,可以使用 \link
命令手动指定:
\link[style={}, labelpos=near start, from layer=0, from node=1, to layer=1, to node=1]
渲染结果如下:
4.5. 完整神经网络示例
使用嵌套循环自动添加所有权重标签:
\foreach \n in {1,...,3}{
\foreach \m in {1,2}{
\link[style={}, labelpos=near start, from layer=0, from node=\n, to layer=1, to node=\m]
}
}
最终完整代码如下:
\documentclass{article}
\usepackage{neuralnetwork}
\begin{document}
\begin{neuralnetwork}
\newcommand{\x}[2]{$x_#2$}
\newcommand{\y}[2]{$y_#2$}
\newcommand{\h}[2]{$h_#2$}
\newcommand{\w}[4] {$w_{#2,#4}$}
\setdefaultlinklabel{\w}
\inputlayer[count=3, bias=false, text=\x]
\hiddenlayer[count=2, text=\h]
\foreach \n in {1,...,3}{
\foreach \m in {1,2}{
\link[style={}, labelpos=near start, from layer=0, from node=\n, to layer=1, to node=\m]
}
}
\outputlayer[count=1, text=\y] \linklayers
\end{neuralnetwork}
\end{document}
5. 使用图形编辑器转换为 LaTeX
除了直接编写 LaTeX 代码,我们还可以使用图形编辑器绘制图形,然后将其导出为 LaTeX 代码。
以下是一些常用工具:
- Python:使用
matplotlib
+tikzplotlib
插件 - MatLab:使用
matlab2tikz
插件 - Blender 2.4:使用
blend2tikz
插件
这种方式特别适合熟悉其他图形工具但仍在学习 LaTeX 的用户。
6. 总结
在本教程中,我们学习了如何使用 LaTeX 绘制图形,重点介绍了 TikZ 和 neuralnetwork 两个包。
我们通过示例展示了如何绘制节点、边、加权边、自环边,并实现了完整的图和神经网络结构。
此外,我们还介绍了将图形编辑器输出转换为 LaTeX 的方法,方便快速生成图形代码。