答案1
这里有一段代码片段,我认为它说明了创建所需插图的要点。
提醒一下:我在代码中作弊了一点(因为我很懒)。我会试着解释一下作弊以及您需要做什么来避免它们或者利用它们。
但首先,这里有一个您想要的插图的部分示例:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{hobby}
\usetikzlibrary{arrows.meta}
\makeatletter
\let\@xp\expandafter
\newcommand\xtractp{\ae@xtractp}
\def\ae@xtractp#1(#2){\def#1{#2}}
%% command to assist in drawing parallel lines out of nodes
\newcommand\shiftdraw{\ae@shiftdraw}
\def\ae@shiftdraw[shift by=#1,#2] (#3) -- (#4);{%%
\path let \p1=($(#4)-(#3)$),
\n1={atan(\y1/\x1)},
\n2={\n1+180},
\n3={\n1+90},
\n4={#1*cos(\n3)},
\n5={#1*sin(\n3)}
in
[draw,#2] ([yshift=\n5,xshift=\n4]#3.\n1) -- ([yshift=\n5,xshift=\n4]#4.\n2);
}
%% commands to assist in drawing the blob
\newcommand\drawblob{\ae@blob}
\def\set@path#1\@nil#2\@nil{\path#2#1;}
\def\ae@blob#1{%%
\let\ae@blob@path\relax{}%%
\foreach \myn in {1,...,#1}
{
\ifx\ae@blob@path\relax
\xdef\ae@blob@path{(b\myn)}%%
\else
\xdef\ae@blob@path{\ae@blob@path .. (b\myn)}%%
\fi
%%\node (N\myn) at (b\myn) {N\myn};
}
\@xp\set@path\ae@blob@path\@nil[draw,use Hobby shortcut,closed=true,fill=gray!80,opacity=0.90]\@nil}
\makeatother
\begin{document}
\begin{tikzpicture}[cn/.style={draw,circle,inner sep=2.5pt,outer sep=1.75pt},>=Stealth]
\node (win) at (-2.5,0.75) {};
\node (yn) at (8,2) {yn};
\path (yn) -- ++(1,0) node[draw,circle] (E) {$-$}
-- ++(0,3) node (yt) {yt}
-- ++(-1,-1) node (wout) {wout};
\def\myc{0}
\foreach \myq in {(0,0),
(0.5,2),
(1,3),
(2,3.5),
(4,3),
(3.5,1),
(3.7,-1),
(2,-0.5)}
{
\expandafter\xtractp\expandafter\myp\myq
\xdef\myc{\number\numexpr\myc+1}
\coordinate (c\myc) at (\myp);
\coordinate (b\myc) at ($(\myp)!-0.6cm!(2,1)$);
%% \draw[->] (2,1) -- (b\myc);
}
%% drawing
\draw[line width=4pt,black!80,->] (win) to[out=30,in=150] (yn);
\drawblob{8}
\foreach \myp in {-1,0,1}
{
\node[inner sep=2.5pt,outer sep=1.75pt,draw,circle] (LN\myp) at (-3,\myp) {};
\draw[gray,->] (LN\myp) -- ++(30:1.35cm);
\draw[gray,->] (LN\myp) -- ++(-30:1.35cm);
}
\draw[->] (yt) -- (E);
\draw[->] (E) -- ++(0,-2) -- ++(-3,0) -- (wout);
\foreach \myc in {1,...,8}
{
\node[circle,inner sep=2.5pt,outer sep=1.75pt,draw] (n\myc) at (c\myc) {};
}
\draw[looseness=8,->] (n2) to[out=100,in=160] (n2);
\draw[->] (n2) -- (n3);
\shiftdraw[shift by=2pt,->] (n3) -- (n4);
\shiftdraw[shift by=-2pt,<-] (n3) -- (n4);
\end{tikzpicture}
\end{document}
在 LaTeX 中绘制插图时,您有几种选择。我最喜欢的两个选择是TikZ
和pstricks
。这里的一切都可以使用 来完成
TikZ
。TikZ
和pstricks
都是套房软件包,提供强大的功能。因此,学习曲线也随之而来。选择一种,坚持使用,并学好它。除非你想让自己的头脑爆炸,否则我不建议在两者之间切换:它们有相似的方法、略有不同的理念以及微妙但突出的语法差异。两者都有很好的文档。但的文档pstricks
分布在多个文件中。的文档TikZ
大体上都包含在一个 pdf 文档中。
一切都是在tikzpicture
环境中绘制的。
您想要在图片中完成的大部分操作都可以通过创建nodes
和/或coordinates
和drawing
在paths
它们之间实现。
Acoordinate
和非常相似。将 a 视为无量纲的node
很有用 。 具有一些复杂的解剖结构。与上述示例相关,具有以下特征:coordinate
node
nodes
nodes
shape
inner sep
outer sep
shape
a 的默认值node
是 a rectangle
。
您首先应该注意到的tikzpicture
是这一行:
\begin{tikzpicture}[cn/.style={draw,circle,inner sep=2.5pt,outer sep=1.75pt},>=Stealth]
我在这里做两件事。
cn
是自定义节点style
我所创造的。
这样可以节省时间,并允许快速轻松地进行更改(如果需要)。对于自定义节点我设置了上面提到的三个功能。我还添加了draw
一个命令,用于显示节点的形状。
我在这一行中所做的是设置整个图片中使用的箭头类型。我正在使用Stealth
,因此我必须加载TikZ
库arrows.meta
。(我没有使用这个库的其他功能。)
我让你阅读了语法文档nodes
(它比我在这里建议的要复杂一些)。但这是我在这里使用的语法:
\node (<node-name>) at (<node location>) {<node content>};
这里绝对必要的是<node content>
。您可以将括号留空,但必须提供它们。另请注意,所有TikZ
命令都以 结尾;
。<node location>
可以是笛卡尔坐标(x,y)
、极坐标或另一个或(angle:radius)
的名称。node
coordinate
我做的前两件事是创建两个名为win
和的节点yn
;我只为节点yn
提供内容。
接下来你会看到一个\path
。路径是图片中大部分内容的支柱TikZ
。(事实上,节点和坐标只是特定类型的路径。)我使用命令\path
来帮助创建图片右侧的三角形路径
\draw[->] (yt) -- (E);
\draw[->] (E) -- ++(0,-2) -- ++(-3,0) -- (wout);
路径上的点通过 连接--
。这个++
符号允许我应用向量到先前绘制的点来移动刷子到下一个点。沿着这条路径,我定义了三个节点:E
、yt
和wout
。
下一段代码可能比必要的要复杂一些,但我很懒(如上所述)。我想在图片中间创建 blob。为此,我使用库TikZ
。hobby
(如上所述,几乎所有TikZ
套件都在其手册中进行了说明。 hobby
是此规则的一个例外。它的文档位于其中,hobby_doc
您可以使用 访问texdoc
。)
这里发生了几件事。我使用循环\foreach
来循环遍历 blob 中包含的点的坐标。问题是宏\coordinate
会查找明确写入的(
和)
。因此,我编写了一个宏,,从括号内\xtractp
提取x
和坐标并将它们分配给。您不必使用这部分代码。您所要做的就是为 blob 中的每个点创建坐标,如下所示y
\myp
\coordinate (c1) at (0,0);
\coordinate (c2) at (0.5,2);
\coordinate (c3) at (1,3);
我们希望斑点在这些点周围形成边框,因此我选择了(2,1)
斑点中间的任意点作为参考来创建斑点的边框点。
\coordinate (b1) at ($(c1)!-0.6cm!(2.1)$)
\coordinate (b2) at ($(c2)!-0.6cm!(2.1)$)
该语法($(<point a>)!<dim>!(<point b>)$)
来自TikZ
库
calc
。这告诉在距离 处沿TikZ
形成的向量创建一个新点 。<point b> - <point a>
<dim>
<point a>
然后我画出斑点。这里我真的很作弊。我创建了一个宏来处理绘制斑点的代码。用手写的话,你需要做的是:
\path[draw,use Hobby shortcut,closed=true,fill=gray!80,opacity=0.90]
(b1) .. (b2) .. (b3) .. (b4) .. (b5) .. (b6) .. (b7) .. (b8);
该语法在库的文档中有解释hobby
。
实际上,在绘制 blob 之前,我会从节点win
到画一条线yn
。顺序对于获得覆盖效果很重要。此外,这也是我opacity=0.90
在绘制 blob 时设置 的原因。
在下一段代码中,我在左侧绘制了交叉箭头。我使用循环\foreach
来实现这一点。我还使用了
++
和极坐标来使箭头指向正确的方向。
我认为,除了最后四行之外,其余代码都是相当不言而喻的:
\draw[looseness=8,->] (n2) to[out=100,in=160] (n2);
\draw[->] (n2) -- (n3);
\shiftdraw[shift by=2pt,->] (n3) -- (n4);
\shiftdraw[shift by=-2pt,<-] (n3) -- (n4);
这些线用于绘制斑点中圆圈之间的连接。
\draw[looseness=8,->] (n2) to[out=100,in=160] (n2);
绘制从圆圈开始并指向圆圈的箭头。使用 来looseness
创建更紧密和更松散的循环。
在最后两行中,我创建了另一个宏来创建节点之间的平行箭头。您可能想要使用这个宏。这里的语法相当强大。我建议您在手册中阅读此语法
TikZ
。
\newcommand\shiftdraw{\ae@shiftdraw}
\def\ae@shiftdraw[shift by=#1,#2] (#3) -- (#4);{%%
\path let \p1=($(#4)-(#3)$),
\n1={atan(\y1/\x1)},
\n2={\n1+180},
\n3={\n1+90},
\n4={#1*cos(\n3)},
\n5={#1*sin(\n3)}
in
[draw,#2] ([yshift=\n5,xshift=\n4]#3.\n1) -- ([yshift=\n5,xshift=\n4]#4.\n2);
}
我伪造的此命令开头的关键字。换句话说,你必须
将shift by=
紧跟在 后面的文本作为\shiftdraw[
。此外,无论您是否要将可选命令传递给路径,都必须在第一个参数后加上逗号。
inner sep
关于和的最后一点outer sep
。
创建inner sep
一个最低限度节点的大小。如果节点的内容太大而无法容纳在最低限度size,TikZ
将扩大节点的大小。
outer sep
有点晦涩,但对于这个问题来说却非常突出。它outer sep
允许箭头接近节点的绘制边框,但不能直接到达。