范围内的 TiKZ 节点名称前缀

范围内的 TiKZ 节点名称前缀

我正在使用 TiKZ 绘制同一图形的两个副本,现在我想在一个副本中的顶点和另一个副本中的顶点之间添加边。我突然想到,如果我可以将每个副本放在单独的范围内,为每个范围命名,并以“面向对象”的方式引用范围内的节点,将节点称为 ,那就太好了<scope name>.<node name>。为了说明这一点,如果我可以做这样的事情,那就太酷了:

\documentclass{article}

\usepackage{tikz}

\begin{document}

\tikzstyle{vertex}=[circle,draw,fill=black!20]

\begin{tikzpicture}

% ---- Copy 1
\begin{scope}[yshift=-32pt,name=G1]
  \node[vertex] (u) at (0, 0) {u};
  \node[vertex] (v) at (0, 0) {v};
\end{scope}

% ---- Copy 2
\begin{scope}[yshift=32pt,name=G2]
  \node[vertex] (u) at (0, 0) {u};
  \node[vertex] (v) at (0, 0) {v};
\end{scope}

\draw (G1.u) -- (G2.v);

\end{tikzpicture}

\end{document}

在这里,我将u范围的节点G1称为G1.u,将v范围的节点G2称为G2.v

在 TiKZ 中可能发生这样的事情吗?

答案1

这是一个简单的 hack,它重新定义了范围内的命名代码以附加前缀。.但是您不能使用 a 作为分隔符,因为这会使解析器感到困惑。我使用了空格,但您可以使用其他东西(一些标点符号,例如.is special,这里有一个列表)。

\documentclass{article}
%\url{http://tex.stackexchange.com/q/128049/86}

\usepackage{tikz}

\begin{document}

\tikzstyle{vertex}=[circle,draw,fill=black!20]

\makeatletter
\tikzset{%
  prefix node name/.code={%
    \tikzset{%
      name/.code={\edef\tikz@fig@name{#1 ##1}}
    }%
  }%
}
\makeatother

\begin{tikzpicture}

% ---- Copy 1
\begin{scope}[yshift=-32pt,prefix node name=G1]
  \node[vertex] (u) at (0, 0) {u};
  \node[vertex] (v) at (0, 0) {v};
\end{scope}

% ---- Copy 2
\begin{scope}[yshift=32pt,prefix node name=G2]
  \node[vertex] (u) at (0, 0) {u};
  \node[vertex] (v) at (0, 0) {v};
\end{scope}

\draw (G1 u) -- (G2 v);

\end{tikzpicture}

\end{document}

请注意,这适用于节点的隐式和显式命名(即通过name=<name>\node (name) ...)。

答案2

scopes在 TiKZ 3.0 中可以使用而不是pics。如果将 aname分配给 a pic,则该名称将充当name prefix并附加在任何内部节点名称之前。

举个例子比我的英语更清楚:

\documentclass{standalone}

\usepackage{tikz}

\begin{document}

%\tikzstyle{vertex}=[circle,draw,fill=black!20]

\tikzset{vertex/.style={circle, draw, fill=black!20},
    myscope/.pic={
        \node[vertex] (-u) at (0,0) {u};
        \node[vertex] (-v) at (0,1) {v};
    }
}

\begin{tikzpicture}

\pic[yshift=-32pt] (G1) {myscope};
\pic[yshift= 32pt] (G2) {myscope};

\draw (G1-u) to[out=30,in=-30] (G2-v);
\draw (G2-u) to[out=210,in=150] (G1-v);

\end{tikzpicture}

\end{document}

在此处输入图片描述

答案3

编辑:看起来我下面的回答完全没有必要,因为 TikZ 有一个标准name prefix键,其作用与我写的非常相似(尽管它没有用空格将前缀与名称分开)。

手册中对这个name prefix钥匙有这样的说法:

此键的值是当前范围内每个节点的前缀。这包括节点的命名(通过 name 键或通过隐式 (⟨name⟩) 语法)以及对节点的任何引用。在范围之外,可以(并且需要)使用由前缀和节点名称组成的“全名”来引用节点。

这样做的最终效果是,您可以将范围开头的名称前缀设置为某个值,然后对范围内的节点使用简短的名称。稍后,在范围之外,您可以通过其全名引用节点:

\tikz {
  \begin{scope}[name prefix = top-]
    \node (A) at (0,1) {A};
    \node (B) at (1,1) {B};
    \draw (A) -- (B);
  \end{scope}
  \begin{scope}[name prefix = bottom-]
    \node (A) at (0,0) {A};
    \node (B) at (1,0) {B};
    \draw (A) -- (B);
  \end{scope}
  \draw [red] (top-A) -- (bottom-B);
}

使用内置功能几乎肯定是最好的选择。


原始答案:

循环空间给出了一个很好的答案,只要您不需要通过无前缀的名称来引用节点,它就可以起作用。

例如,如果你\draw (u) -- (v);在每个作用域内添加一个,就会出现一个有点神秘的错误,Package pgf Error: No shape named u is known.

更好的选择是改变定义,prefix node name不改变名称的记录方式,而是添加带有前缀的别名。

\tikzset{
  prefix node name/.style={%
    /tikz/name/.append style={%
      /tikz/alias={#1 ##1}%
    }%
  }
}

本质上,添加prefix node name=foo到范围将导致name=bar范围内的所有内容都表现得好像它是一样name=bar,alias={foo bar}

这里是对 Loop Space 示例的修改,使用了上面的定义,prefix node name并对图片进行了轻微的修改(因此节点不会彼此重叠),并\draw添加了一些 s 来显示效果。

\documentclass{article}
\usepackage{tikz}

\tikzstyle{vertex}=[circle,draw,fill=black!20]

\tikzset{
  prefix node name/.style={%
    /tikz/name/.append style={%
      /tikz/alias={#1 ##1}%
    }%
  }
}

\begin{document}
\begin{tikzpicture}

% ---- Copy 1
\begin{scope}[yshift=32pt,prefix node name=G1]
  \node[vertex] (u) at (0, 0) {u};
  \node[vertex] (v) at (2, 0) {v};
  \draw (u) -- (v);
\end{scope}

% ---- Copy 2
\begin{scope}[yshift=-32pt,prefix node name=G2]
  \node[vertex] (u) at (0, 0) {u};
  \node[vertex] (v) at (2, 0) {v};
  \draw (u) -- (v);
\end{scope}

\draw[->] (G1 u) -- (G2 v);
\end{tikzpicture}

\end{document}

在此处输入图片描述

相关内容