3

As shown below, the node positions have been changed when using chain. How to fix it?

node-position-in-chain

\documentclass[tikz]{standalone}

\usetikzlibrary{positioning, chains}

\begin{document}
\begin{tikzpicture}[start chain = arc]
  % with chain
  \foreach \p in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} {
    \node [draw, circle, minimum size = 6pt, on chain, join] at (\p) {};
  }
  % without chain
  \begin{scope}[yshift = -3cm]
    \foreach \p in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} {
      \node [draw, circle, minimum size = 6pt] at (\p) {};
    }
  \end{scope}
\end{tikzpicture}
\end{document}
hengxin
  • 2,371

2 Answers2

2

Chains come with a predefined node distance. If you set it to 0, or even better, to an appropriate negative distance, you avoid the shift. What is this appropriate distance? You give the nodes a minimum size of 6pt, but you also go into a 45 degree direction. This suggests that this distance is 6pt/sqrt(2) plus some outer sep. At least numerically this seems to fit rather well.

\documentclass[tikz,border=3.14mm]{standalone}

\usetikzlibrary{positioning, chains,calc}

\begin{document}
\begin{tikzpicture}[start chain = arc]
  % with chain, no distance modified
  \foreach \p [count=\X] in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} {
    \node [draw, circle, minimum size = 6pt, on chain, join] at (\p) (u-\X) { };
      \draw let \p1=(u-\X) in node[anchor=south] at (u-\X.north) {\x1}
       node[anchor=north] at (u-\X.south) {\y1};
  }
  % chain, node distance set to 0
  \begin{scope}[yshift =-3cm,start chain=arc2,node distance=0pt]
  \foreach \p [count=\X] in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} {
    \node [draw, circle, minimum size = 6pt, on chain, join] at (\p) (m-\X) { };
      \draw let \p1=(m-\X) in node[anchor=south] at (m-\X.north) {\x1}
       node[anchor=north] at (m-\X.south) {\y1};
  }
  \end{scope}
  % chain, 
  \begin{scope}[yshift =-6cm,start chain=arc3,node distance={-(6/sqrt(2))*1pt
  -2*\pgfkeysvalueof{/pgf/outer xsep}-\pgflinewidth/sqrt(2)}]
  \foreach \p [count=\X] in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} {
    \node [draw, circle, minimum size = 6pt, on chain, join] at (\p) (n-\X) { };
      \draw let \p1=(n-\X) in node[anchor=south] at (n-\X.north) {\x1}
       node[anchor=north] at (n-\X.south) {\y1};
  }
  \end{scope}
  % without chain
  \begin{scope}[yshift = -9cm]
    \foreach \p [count=\X] in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} {
      \node [draw, circle, minimum size = 6pt] at (\p)
      (l-\X) {};
      \draw let \p1=(l-\X) in node[anchor=south] at (l-\X.north) {\x1}
       node[anchor=north] at (l-\X.south) {\y1};
    }
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Whether this is the full explanation, I don't know.

  • 1
    Of course, chains are made to avoid specifying their location explicitly, so it is not too surprising that the explicit placement fails. –  Sep 10 '18 at 03:34
1

When you specify no direction, i.e. a placement rule, after the name of your chain in the form of going direction or placed direction, the chain uses the chain default direction which is going right.

This means, for every node (except the first), the option right = of \tikzchainprevious (of the positioning library) will be executed. This is essentially:

  1. at = (\tikzchainprevious.east),
  2. xshift = node distance and
  3. anchor = west.

Since you use at (\p), the first setting is overwritten but both the transformation and the anchor remain.

Since the default node distance is 1cm every node after the first will be shifted to the right by that distance and will placed there with its west anchor.

This can be seen very good when a grid is added to the diagram since the nodes now touch the vertical lines with the left side.


If you want to use the chains library without the automatic placement just use nothing as the direction.

Alternatively, you could also use = for the direction but both the = as well as the nothing needs special care because of how PGFKeys works.

You will need

  • start chain = {arc going },
  • start chain = arc going {},
  • start chain = arc going {=} or
  • start chain = {arc going =}.

If the direction contains a = then it will just be executed when the node is placed directly (without it getting turned into = of \tikzchainprevious).

But both cases will be ignored silently by PGFKeys because it sees an empty key name.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{chains}
\begin{document}
\begin{tikzpicture}[
  every on chain/.append style=join,
  nodes={draw, circle, minimum size = 6pt}
]
\draw[help lines] (-.25,-6.25) grid (7.5,2.5);
\scoped[start chain = arc, nodes=on chain]
  \foreach \p in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}}
    \node at (\p) {};

\scoped[start chain = arc going {}, nodes = on chain, yshift=-3cm] \foreach \p in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} \node at (\p) {};

\scoped[yshift=-6cm] \foreach \p in {{0,0}, {1,1}, {2,1.5}, {3,2}, {4, 1.5}, {5,1}, {6,0}} \node at (\p) {}; \end{tikzpicture} \end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821