![在 tikz 中创建常见交换图的宏](https://linux22.com/image/249064/%E5%9C%A8%20tikz%20%E4%B8%AD%E5%88%9B%E5%BB%BA%E5%B8%B8%E8%A7%81%E4%BA%A4%E6%8D%A2%E5%9B%BE%E7%9A%84%E5%AE%8F.png)
我目前正在排版一份文档,该文档需要许多形状和结构相同但顶点和边上的标签不同的交换图。例如,我想要一个描述代数结合结构的交换图。我可以用以下方法做到这一点:
\begin{equation}
\begin{tikzpicture}[baseline=(current bounding box.center)]
\matrix(m)[matrix of math nodes,
row sep=2.6em, column sep=2.8em,
text height=2ex, text depth=0.5ex]
{(A\otimes A)\otimes A& & A\otimes (A\otimes A)\\
A\otimes A& &A\otimes A\\
&A& \\};
\path[->,font=\normalsize,>=angle 90]
(m-1-1) edge node[auto] {$\mu\otimes Id$} (m-2-1)
(m-2-1) edge node[auto] {$\mu$} (m-3-2)
(m-1-3) edge node[auto] {$ Id\otimes\mu$} (m-2-3)
(m-2-3) edge node[auto] {$ \mu$} (m-3-2);
\path[<->, font=\normalsize,>=angle 90]
(m-1-1) edge node[auto] {$\alpha$} (m-1-3);
\end{tikzpicture}
\end{equation}
在同一节中,我还想使用交换图来表达群的单半群结构。在我的文档中,这是完全相同的代码,但标签不同。随着我的继续,我知道这是一个我可能会经常使用的图表,并且不想将这个确切的代码复制并粘贴到每个新文档中。
我天真地尝试使用\newcommand{\monoid}[8]{...}
来包装整个内容,但是这没有用。有没有办法在这个环境周围定义一个宏,这样我就可以只指定我需要的参数,而不必每次都复制和粘贴整个块,这样就很混乱了?
答案1
您需要使用键 替换 TikZ 矩阵中的“与”符号ampersand replacement=<macro>
,其中<macro>
可以是\&
,例如 。
这是您的代码作为命令。我使用了PGF/TikZ:如何将字符串存储在数组中?使用列表而不是单独的标签参数。您的图表
然后可以使用创建
\monoid{
(A\otimes A)\otimes A,
A\otimes (A\otimes A),
A\otimes A,
A\otimes A,
A,
$\mu\otimes Id$,
$\mu$,
$ Id\otimes\mu$,
$ \mu$,
$\alpha$
}
完整代码如下:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix,arrows}
\usepackage{xparse}
\usepackage{etoolbox}
\newcounter{listtotal}\newcounter{listcntr}%
\NewDocumentCommand{\argument}{o}{%
\setcounter{listtotal}{0}\setcounter{listcntr}{-1}%
\renewcommand*{\do}[1]{\stepcounter{listtotal}}%
\expandafter\docsvlist\expandafter{\argumentarray}%
\IfNoValueTF{#1}
{\namesarray}% \names
{% \names[<index>]
\renewcommand*{\do}[1]{\stepcounter{listcntr}\ifnum\value{listcntr}=#1\relax##1\fi}%
\expandafter\docsvlist\expandafter{\argumentarray}}%
}
\newcommand{\monoid}[1]{
\def\argumentarray{#1}
\begin{tikzpicture}[baseline=(current bounding box.center)]
\matrix(m)[
matrix of math nodes,
ampersand replacement=\&,
row sep=2.6em,
column sep=2.8em,
text height=2ex,
text depth=0.5ex
]
{
\argument[0] \& \& \argument[1]\\
\argument[2] \& \& \argument[3]\\
\& \argument[4] \& \\
};
\path[->,font=\normalsize,>=angle 90]
(m-1-1) edge node[auto] {\argument[5]} (m-2-1)
(m-2-1) edge node[auto] {\argument[6]} (m-3-2)
(m-1-3) edge node[auto] {\argument[8]} (m-2-3)
(m-2-3) edge node[auto] {\argument[9]} (m-3-2);
\path[<->, font=\normalsize,>=angle 90]
(m-1-1) edge node[auto] {\argument[10]} (m-1-3);
\end{tikzpicture}
}
\begin{document}
\monoid{
(A\otimes A)\otimes A,
A\otimes (A\otimes A),
A\otimes A,
A\otimes A,
A,
$\mu\otimes Id$,
$\mu$,
$ Id\otimes\mu$,
$ \mu$,
$\alpha$
}
\end{document}
答案2
另一种方法:
- 用于
tikz-cd
简单构造交换图 - 使用
arrayjobx
元素的包
好处:
- 更短的图表代码,箭头直接位于元素内
- 您不必每次调用时都编写 9 个参数
\monoid
,如果图表类似,您可以只修改特定的数组参数,例如通过并再次\monoidelements(1)={A'\otimes A'}
调用\monoid
\documentclass{article}
\usepackage{arrayjobx}
\newarray{monoidelements}
\usepackage{tikz-cd}
\newcommand{\monoid}[1]{
\begin{tikzcd}[->,font=\normalsize,>=angle 90,ampersand replacement=\&]
#1(1) \arrow{d}{#1(6)} \arrow[<->]{rr}{\alpha}\& \& #1(2) \arrow{d}{#1(7)}\\
#1(3) \arrow{dr}{#1(8)} \& \& #1(4)\arrow{dl}{#1(9)}\\
\& #1(5) \&
\end{tikzcd}}
\begin{document}
\readarray{monoidelements}{(A\otimes A)\otimes A\otimes A&A\otimes (A\otimes A)
&A\otimes A&A\otimes A&A&\mu\otimes Id&Id\otimes\mu&\mu&\mu\otimes Id}
\monoid{\monoidelements}
\end{document}
答案3
作为评论,这个答案太长了,因为它只是使用基于的较短语法重写了Jake的答案expl3
:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix,arrows}
\usepackage{xparse}
\ExplSyntaxOn
\seq_new:N \l_jake_monoid_seq
\NewDocumentCommand{\monoid}{m}
{
\seq_set_split:Nnn \l_jake_monoid_seq { , } { #1 }
\domonoid
}
\NewDocumentCommand{\argument}{o}
{
\IfNoValueTF{#1}
{ \seq_use:N \l_jake_monoid_seq }
{ \seq_item:Nn \l_jake_monoid_seq { #1 } }
}
\ExplSyntaxOff
\NewDocumentCommand{\domonoid}{}
{
\begin{tikzpicture}[baseline=(current bounding box.center)]
\matrix(m)[
matrix of math nodes,
ampersand replacement=\&,
row sep=2.6em,
column sep=2.8em,
text height=2ex,
text depth=0.5ex
]
{
\argument[0] \& \& \argument[1]\\
\argument[2] \& \& \argument[3]\\
\& \argument[4] \& \\
};
\path[->,font=\normalsize,>=angle 90]
(m-1-1) edge node[auto] {\argument[5]} (m-2-1)
(m-2-1) edge node[auto] {\argument[6]} (m-3-2)
(m-1-3) edge node[auto] {\argument[8]} (m-2-3)
(m-2-3) edge node[auto] {\argument[9]} (m-3-2);
\path[<->, font=\normalsize,>=angle 90]
(m-1-1) edge node[auto] {\argument[10]} (m-1-3);
\end{tikzpicture}
}
\begin{document}
\monoid{
(A\otimes A)\otimes A,
A\otimes (A\otimes A),
A\otimes A,
A\otimes A,
A,
$\mu\otimes \mathit{Id}$,
$\mu$,
$ \mathit{Id}\otimes\mu$,
$ \mu$,
$\alpha$
}
\end{document}
该\monoid
宏执行两项操作:它从其参数设置一个序列,并调用\domonoid
与 Jake 的相同的序列\monoid
。请注意\domonoid
必须用 来定义\ExplSyntaxOff
,因为 TikZ 键中的空格很重要。
的定义\argument
是很多比 更容易etoolbox
。
注意:为了得到更好的形式ID,最好使用\mathit{Id}
。
我们也可以对 Stefan Kottwitz 的回答使用类似的想法
\documentclass{article}
\usepackage{xparse}
\usepackage{tikz-cd}
\NewDocumentCommand{\monoid}{m}
{
\makeargument{#1}
\begin{tikzcd}[->,font=\normalsize,>=angle 90,ampersand replacement=\&]
\argument{0} \arrow{d}{\argument{5}} \arrow[<->]{rr}{\alpha}\& \& \argument{1} \arrow{d}{\argument{6}}\\
\argument{2} \arrow{dr}{\argument{7}} \& \& \argument{3}\arrow{dl}{\argument{8}}\\
\& \argument{4} \&
\end{tikzcd}
}
\ExplSyntaxOn
\seq_new:N \l_sk_monoid_seq
\cs_new:Npn \makeargument #1
{ \seq_set_split:Nnn \l_sk_monoid_seq { & } { #1 } }
\cs_new:Npn \argument #1
{ \seq_item:Nn \l_sk_monoid_seq {#1} }
\ExplSyntaxOff
\begin{document}
\monoid{
(A\otimes A)\otimes A\otimes A &
A\otimes (A\otimes A) &
A\otimes A &
A\otimes A &
A &
\mu\otimes\mathit{Id} &
\mathit{Id}\otimes\mu &
\mu &
\mu\otimes\mathit{Id}
}
\end{document}