我对 TikZ 还只是个新手。
以下 MWE 看起来相当简单直接,但它的编译速度比我认为的要慢得多。有人能解释一下发生了什么吗?或者可能提出一些建议,这些建议仍然会产生相同的图像,但编译速度更快?
最初,我以为可能是calc
库导致速度变慢。MWE 展示了我如何重写以避免使用calc
。旧方法只是被注释掉了。
\documentclass{article}
\usepackage[margin=0.5in]{geometry}
\usepackage{tikz}
%%\usetikzlibrary{calc}
\usetikzlibrary{arrows.meta}
\makeatletter
\def\@aem(#1)#2;{\node[anchor=base] at (#1) {#2};
\draw (#1/nw) rectangle (#1/se);
\path (#1) + (0,6ex) coordinate (#1/t)
+ (0,2.5ex) coordinate (#1/h);
%%\coordinate (#1/t) at ($(#1)+(0,6ex)$);
%%\coordinate (#1/h) at ($(#1)+(0,2ex)$);
\draw[line width=2pt,arrows=-{Stealth[length=2ex,width=1.5ex]}] (#1/t) -- (#1/h); }
\def\@aeo(#1)#2;{\node[inner sep=1ex,anchor=base] at (#1) {#2}; \draw (#1/nw) rectangle (#1/se);}
\def\@aex(#1)#2;{\node[anchor=base] at (#1) {#2};}
\def\@aef(#1)#2;{\node[anchor=base] at (#1) {\textcolor{gray!20}{#2}};}
\def\ae#1#2#3{\csname @ae#1\endcsname(p#3){#2};}
\makeatother
\def\aemarkup#1{%%
\begin{tikzpicture}
\foreach \x in {0,1,2,...,14}
{
\path (0,0) -- (\x*0.45cm,0) coordinate (p\x)
+ (115:3ex) coordinate (p\x/nw)
+ (-20:1.5ex) coordinate (p\x/se);
\draw (p\x) ++(0,-0.5ex) -- ++(0,-2ex);
%%\coordinate (p\x) at ($(0,0)+\x*(0.45cm,0)$);
%%\coordinate (p\x/nw) at ($(p\x)+(115:3ex)$);
%%\coordinate (p\x/se) at ($(p\x)+(-20:1.5ex)$);
%%\draw (p\x) -- ($(p\x)-(0,2ex)$);
}
\foreach \y [count=\yi from 0] in {#1}
{ \expandafter\ae\y\yi}
\end{tikzpicture}\par}
\begin{document}
Diagram:
\aemarkup{mx , ox , ox , ox , ox , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}
\aemarkup{fx , ox , mx , ox , ox , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}
\aemarkup{fx , ox , fx , ox , mx , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}
\aemarkup{fx , ox , fx , ox , fx , ox , mx , oM , ox , ox , ox , oa , ox , ob , oc}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , mx , ox , ox , oa , ox , ob , oc}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , mx , oa , ox , ob , oc}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , fx , oa , mx , ob , oc}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , fx , oa , fx , ob , mc}
\aemarkup{mx , ox , ox , oM , ox , oa , ob , xc}
\aemarkup{fx , ox , mx , oM , ox , oa , ob , xc}
\aemarkup{fx , ox , fx , oM , mx , oa , ob , xc}
\aemarkup{fx , ox , fx , oM , fx , oa , mb , xc}
\aemarkup{mx , oM , oa , xb , xc}
\aemarkup{fx , oM , ma , xb , xc}
\aemarkup{mM , xa , xb , xc}
\end{document}
答案1
我会让代码更简单。
- 使用
chains
图书馆。 - 充分利用节点的功能:
text *
键,以便所有节点具有相同的大小,append after command
有助于将箭头和小线条放置在底部。
- 使用样式。
我还使用了node contents
CVS 版本中引入的密钥(相对容易实现但非常有用)。请注意,该节点不再有文本组({<text>}
缺失)。
需要\aemarkup
第三个(第二个强制)参数,表示最大行数/节点数。如果给出的循环元素少于,则使用它来填充行#3
。这是您的硬编码14
。
代码
\documentclass[varwidth]{standalone}
\usepackage{tikz} \usetikzlibrary{chains,arrows.meta}
\tikzset{
my node/.style 2 args={#1 style/.try, node contents={#2}},
x style/.style={text width=\widthof{M}, text depth=+0pt, text height=\heightof{M}+2pt,
align=center, inner xsep=+0.5pt, inner ysep=+1pt,
append after command={(\tikzlastnode.south) edge ++ (down:+1.5ex)}},
f style/.style={x style, text=gray},
o style/.style={x style, draw},
m style/.style={o style,
append after command={% the arrow from above
(\tikzlastnode.north) edge
[line width=+2pt, arrows={Stealth[length=+2ex,width=+1.5ex]}-] ++ (up:+3.5ex)}}}
\newcommand*\aemarkup[3][]{
\tikzpicture[start chain=going mid right,node distance=+.1em,#1]
\foreach \aeI[count=\cnt from 2,remember=\cnt] in {#2}% \cnt will be global after this
\node[on chain,my node/.expand once=\aeI];
\ifnum\cnt>#3\else
\foreach \aeI in {\cnt,...,#3}\node[on chain, my node={x}{}];
\fi
\endtikzpicture\par}
\begin{document}
Diagram:
\aemarkup{mx , ox , ox , ox , ox , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , mx , ox , ox , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , mx , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , mx , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , mx , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , mx , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , fx , oa , mx , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , fx , oa , fx , ob , mc}{15}
\aemarkup{mx , ox , ox , oM , ox , oa , ob , xc}{15}
\aemarkup{fx , ox , mx , oM , ox , oa , ob , xc}{15}
\aemarkup{fx , ox , fx , oM , mx , oa , ob , xc}{15}
\aemarkup{fx , ox , fx , oM , fx , oa , mb , xc}{15}
\aemarkup{mx , oM , oa , xb , xc}{15}
\aemarkup{fx , oM , ma , xb , xc}{15}
\aemarkup{mM , xa , xb , xc}{15}
\end{document}
输出
代码 (PGF)
为了进行比较,仅使用 PGF(和)进行快速而粗糙的实现pgffor
。
text width
键、text depth
和(TikZ 键)的效果text height
通过规则(本质上是支柱)和 LaTeX 的 重现\makebox
。设置描边和文本颜色的键draw
和text
是通过设置 TeX 宏的基本键实现的。箭头也是如此。
该库的效果是通过条件和chains
硬编码的。\ifnum\cnt
\pgftransformshift
TikZ 确实在幕后做了很多事情,不是吗?
\documentclass[varwidth]{standalone}
\usepackage{pgf,pgffor} \usepgflibrary{arrows.meta}
\pgfset{draw path/.code=\def\aeusepath{stroke},
none path/.code=\def\aeusepath{discard},
gray text/.code=\def\aenodesetupcol{\color{gray}}}
\let\arrowpath\relax
\let\aenodesetupcol\relax
\def\Arrowpath{%
\edef\linewidth{\the\pgflinewidth}
\pgfsetlinewidth{+2pt}
\pgfsetstrokecolor{black}
\pgfpathmoveto{\pgfpointanchor{chain-\cnt}{north}}
\pgfpathlineto{\pgfpointadd{\pgfpointanchor{chain-\cnt}{north}}{\pgfqpoint{0pt}{15pt}}}
\pgfsetarrowsstart{Stealth[length=+2ex,width=+1.5ex]}
\pgfusepath{stroke}
\pgfsetlinewidth{\linewidth}}
\pgfset{
x style/.style={inner xsep=+0.5pt, inner ysep=+1pt, none path},
f style/.style={x style, gray text},
o style/.style={x style, draw path},
m style/.style={o style, /utils/exec=\let\arrowpath\Arrowpath}}
\newcommand*\aenodesetup[1]{%
\vrule height1emdepth0ptwidth0pt\relax
\makebox[1em][c]{\aenodesetupcol#1}}
\newcommand*\aeaux[2]{%
\begingroup
\pgfset{#1 style}
\ifnum\cnt=1
\pgfnode{rectangle}{base}{\aenodesetup{#2}}{chain-\cnt}{\pgfusepath{\aeusepath}}
\else
\begingroup
\pgftransformshift{
\pgfpointadd{\pgfpointanchor{chain-\the\numexpr\cnt-1\relax}{base east}}
{\pgfqpoint{2pt}{0pt}}}
\pgfnode{rectangle}{base west}{\aenodesetup{#2}}{chain-\cnt}
{\pgfusepath{\aeusepath}}
\endgroup
\fi
\pgfsetstrokecolor{black}
\pgfpathmoveto{\pgfpointanchor{chain-\cnt}{south}}
\pgfpathlineto{\pgfpointadd{\pgfpointanchor{chain-\cnt}{south}}{\pgfqpoint{0pt}{-6pt}}}
\pgfusepath{stroke}
\arrowpath
\endgroup}
\newcommand*\aemarkup[3][]{
\pgfpicture[#1]
\foreach \aeI[count=\cnt,remember=\cnt] in {#2}% \cnt will be global after this
{\expandafter\aeaux\aeI}
\ifnum\cnt=#3\else
\edef\Cnt{\the\numexpr\cnt+1\relax}
\foreach \cnt in {\Cnt,...,#3}{\aeaux{x}{}}
\fi
\endpgfpicture\par}
\begin{document}
Diagram:
\aemarkup{mx , ox , ox , ox , ox , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , mx , ox , ox , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , mx , ox , ox , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , mx , oM , ox , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , mx , ox , ox , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , mx , oa , ox , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , fx , oa , mx , ob , oc}{15}
\aemarkup{fx , ox , fx , ox , fx , ox , fx , oM , fx , ox , fx , oa , fx , ob , mc}{15}
\aemarkup{mx , ox , ox , oM , ox , oa , ob , xc}{15}
\aemarkup{fx , ox , mx , oM , ox , oa , ob , xc}{15}
\aemarkup{fx , ox , fx , oM , mx , oa , ob , xc}{15}
\aemarkup{fx , ox , fx , oM , fx , oa , mb , xc}{15}
\aemarkup{mx , oM , oa , xb , xc}{15}
\aemarkup{fx , oM , ma , xb , xc}{15}
\aemarkup{mM, xa, xb, xc}{15}
\end{document}