下面是使用 tikzmark 绘制连接树中两个子节点的箭头的 MWE:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
%\tikzexternalize
\usetikzlibrary{tikzmark}
\begin{document}
\begin{tikzpicture}
\node {A}
child {node {\subnode{end}{B}}}
child {node {C \subnode{start}{B} E}};
\end{tikzpicture}
\begin{tikzpicture}[
remember picture,
overlay]
\draw[->] (start.south) to [out=south west,in=south east] (end.south);
\end{tikzpicture}
\end{document}
正如预期的那样,这会产生以下输出(使用 调用pdflatex
)-shell-escape
:
但是,如果%\tikzexternalize
取消注释,编译就会失败,并出现以下错误:
! Package pgf Error: No shape named start is known.
tikzmark 和 tikz externalize 是否不兼容?如果是,它们是否从根本上不相容?
编辑后添加:如果从根本上不兼容,是否有其他方法可以执行类似这篇文章中的图像的操作 - 即用(例如)箭头瞄准子节点?
答案1
这是适用于您给出的示例的一种有点黑客的方法。尝试一些更复杂的方法,看看它有多强大。
第一个问题是,当外部化时,TikZ 会调用\nofiles
,因此不会将任何内容写入辅助文件。由于tikzmark
依赖于写入辅助文件的内容,因此这对于使其与外部化配合使用是一个相当大的障碍。为了实现这一点,我们窃取了https://tex.stackexchange.com/a/75030/86,这也意味着我们在外化时必须使用list and make
而不是system call
。
但这并不能解决所有问题,因为即使将内容写入辅助文件,它也不会正确写入。偏移量可能是由于页面裁剪造成的,但也可能完全是由于其他原因造成的。幸运的是,它是一致的。所以我们需要做的是将子节点放在某个已知的地方(例如,在原点),然后使用它来计算偏移量。然后我们可以根据这个偏移量调整所有其他子节点。
为了避免冲突,我定义了一个新的子节点命令\extsubnode
来执行此调整。
\documentclass{article}
%\url{https://tex.stackexchange.com/q/255543/86}
\usepackage{tikz}
\usetikzlibrary{external}
\let\oldnofiles=\nofiles
\let\nofiles=\relax
\tikzexternalize[mode=list and make]
\let\nofiles=\oldnofiles
\usetikzlibrary{tikzmark}
\makeatletter
\tikzset{
every picture/.style={
execute at begin picture={%
\edef\outermostid{\pgfpictureid}%
\node {\subnode{origin\outermostid}{}};
}
}
}
\newcommand\extsubnode[3][]{%
\begingroup
\pgfmark{#2}%
\setbox\pgfnodeparttextbox=\hbox\bgroup #3\egroup
\def\tikz@shape{rectangle}%
\def\tikz@anchor{center}%
\def\tikz@fig@name{#2}%
\tikzset{every subnode/.try,#1}%
\pgfpointorigin
% there is a spurious space inserted by the next point scan so we
% box it to ignore it
\setbox\tikz@tempbox=\hbox\bgroup
\tikz@scan@one@point\pgfutil@firstofone(origin\outermostid)\relax
\global\pgf@xa=\pgf@x
\global\pgf@ya=\pgf@y
\egroup
\tikz@scan@one@point\pgfutil@firstofone(pic cs:#2)\relax
\advance\pgf@x by -\pgf@xa
\advance\pgf@y by -\pgf@ya
\advance\pgf@x by .5\wd\pgfnodeparttextbox
\advance\pgf@y by .5\ht\pgfnodeparttextbox
\advance\pgf@y by -.5\dp\pgfnodeparttextbox
\pgftransformshift{}%
\setbox\@tempboxa=\hbox\bgroup
\pgfutil@ifundefined{pgf@sh@s@\tikz@shape}%
{\PackageError{pgf}{Unknown shape ``\tikz@shape''}{}}%
{%
{%
\let\pgf@sh@savedmacros=\pgfutil@empty% MW
\let\pgf@sh@savedpoints=\pgfutil@empty%
\def\pgf@sm@shape@name{\tikz@shape}% CJ % TT added prefix!
\csname pgf@sh@s@\tikz@shape\endcsname%
\pgf@sh@savedpoints%
\pgf@sh@savedmacros% MW
\pgftransformshift{%
\pgf@sh@reanchor{\tikz@shape}{\tikz@anchor}%
\pgf@x=-\pgf@x%
\pgf@y=-\pgf@y%
}%
\expandafter\pgfsavepgf@process\csname pgf@sh@sa@\tikz@fig@name\endcsname{%
\pgf@sh@reanchor{\tikz@shape}{\tikz@anchor}% FIXME : this is double work!
}%
% Save the saved points and the transformation matrix
\edef\pgf@node@name{\tikz@fig@name}%
\ifx\pgf@node@name\pgfutil@empty%
\else%
\expandafter\xdef\csname pgf@sh@ns@\pgf@node@name\endcsname{\tikz@shape}%
\edef\pgf@sh@@temp{\noexpand\gdef\expandafter\noexpand\csname pgf@sh@np@\pgf@node@name\endcsname}%
\expandafter\pgf@sh@@temp\expandafter{\pgf@sh@savedpoints}%
\edef\pgf@sh@@temp{\noexpand\gdef\expandafter\noexpand\csname pgf@sh@ma@\pgf@node@name\endcsname}% MW
\expandafter\pgf@sh@@temp\expandafter{\pgf@sh@savedmacros}% MW
\pgfgettransform\pgf@temp
\expandafter\xdef\csname pgf@sh@nt@\pgf@node@name\endcsname{\pgf@temp}%
\expandafter\xdef\csname pgf@sh@pi@\pgf@node@name\endcsname{\pgfpictureid}%
\fi%
}%
}%
\egroup
\box\pgfnodeparttextbox
\endgroup
}
\makeatother
\begin{document}
\begin{tikzpicture}
\node {A}
child {node[draw] {\extsubnode{end}{B}}}
child {node {C\extsubnode{start}{B}E}};
\draw[->] (start.south) to [out=south
west,in=south east] (end.south);
\end{tikzpicture}
\end{document}
答案2
已提交供您参考。下面是一个 MWE,通过使用standalone
代替 ,效果非常接近external
。主文件 ( test.tex
) 如下所示:
\documentclass{article}
\usepackage[mode=buildnew]{standalone}
\begin{document}
\includestandalone{tree}
\end{document}
和tree.tex
像这样(基本上粘贴了 Gonzalo Medina 给出的答案这里):
\documentclass[border=20pt]{standalone}
%necessary for tikzmark and xetex to play nicely
\newcount\pdftexversion
\pdftexversion140 \def\pgfsysdriver{pgfsys-dvipdfm.def}
\usepackage{forest}
\usetikzlibrary{tikzmark}
\begin{document}
\begin{forest}
for tree={s sep=20pt}
[A t\subnode{endc}{e}st text
[B
[\subnode{enda}{C},
]
]
[D
[\subnode{endb}{E}
]
[\subnode{startc}{F}
[G
]
[H
[\subnode{startb}{John} see \subnode{starta}{x}
]
]
]
]
]
\end{forest}
\begin{tikzpicture}[
remember picture,
overlay,
>=latex
]
\draw[cyan,thick,->]
(starta.south) --
++(0pt,-10pt) -|
(enda.south);
\draw[red!80!black,thick,->]
(startb.south) --
++(0pt,-5pt) -|
(endb.south);
\draw[green!80!black,thick,->]
(startc) to[out=60,in=90,looseness=1.4]
(endc.north);
\end{tikzpicture}
\end{document}
(这border=20pt
是必要的,因为standalone
没有考虑移动箭头。)
使用编译主文件latexmk -pvc -xelatex test.tex --shell-escape
会得到一些看起来正确的东西。进步了!但是,latexmk
然后进入无限循环。原因尚不清楚。修改.latexmkrc
为详细的这里似乎没有什么帮助,latexmk
用-recorder-
旗帜呼叫也没有用。