4

I want to use a foreach loop to position tikz nodes below each other.

\documentclass[tikz]{standalone}
\usetikzlibrary[positioning]
\begin{document}
\begin{tikzpicture}
  \node (n1){First};
  \foreach \x in {2,...,6}{%
    \pgfmathparse{\x-1}%
    \node [below = of n\pgfmathresult](n\x)  {\x};
  }
\end{tikzpicture}
\end{document}

numbers drifting to the right

Why are the numbers drifting to the right!?

Seamus
  • 73,242

4 Answers4

10

\pgfmathparse evaluates to a float number: 1.0, 2.0, ... Then, you get below = of n1.0. The .0 is an border anchor, meaning the border at an angle of 0°, the same as n.east. This explains the shift to the right. The lower node's center is placed below the upper node's right side.

The .0 can be stripped by \pgfmathtruncatemacro, for example:

\documentclass[tikz]{standalone}
\usetikzlibrary[positioning]
\begin{document}
\begin{tikzpicture}
  \node (n1){First};
  \foreach \x in {2,...,6}{%
    \pgfmathtruncatemacro{\lastx}{\x - 1}
    \node [below = of n\lastx](n\x)  {\x};
  }
\end{tikzpicture}
\end{document}

An alternative is key remember in the \foreach loop to remember the previous value without the need to calculate it:

\documentclass[tikz]{standalone}
\usetikzlibrary[positioning]
\begin{document}
\begin{tikzpicture}
  \node (n1){First};
  \foreach \x [remember=\x as \lastx (initially 1)] in {2,...,6}{%
    \node [below = of n\lastx](n\x)  {\x};
  }
\end{tikzpicture}
\end{document}
Heiko Oberdiek
  • 271,626
4

Zarko and Heiko Oberdiek and explained the reason of the problem (\pgfmathparse producing a floating point result unless told otherwise; .0 being interpreted as a TikZ anchor specification: 0° = east anchor).

Here are some other possibilities that don't bet on \node not overwriting \pgfmathresult:

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}

\begin{document} \begin{tikzpicture} \node (n1) {First}; \foreach \x in {2,...,6} { \pgfmathtruncatemacro{\xMinusOne}{\x-1} \node [below = of n\xMinusOne] (n\x) {\x}; } \end{tikzpicture} \end{document}

and

\documentclass[tikz]{standalone}
\usetikzlibrary{positioning}

\begin{document} \begin{tikzpicture} \node (n1) {First} foreach[evaluate=\x as \xMinusOne using int(\x - 1)] \x in {2,...,6} { node[below = of n\xMinusOne] (n\x) {\x} }; \end{tikzpicture} \end{document}

enter image description here

frougon
  • 24,283
  • 1
  • 32
  • 55
4

Here's another possibility using tikz library chains:

\documentclass[tikz]{standalone}
\usetikzlibrary{chains}

\begin{document} \begin{tikzpicture} \begin{scope}[start chain=1 going below, nodes={on chain=1}] \node (n1) {First} foreach \x in {2,...,6} { node (n\x) {\x} }; \end{scope} \end{tikzpicture} \end{document}

muzimuzhi Z
  • 26,474
3

You need node position you should calculate as \pgfmathparse{int(\x-1)}%, with out int coordinates are n1.0 which are not valid format in your case (numbers after decimal point determine anchor on node border) for positioning of nodes in image.

Complete MWE:

\documentclass[tikz]{standalone}
\usetikzlibrary[positioning]
\begin{document}
\begin{tikzpicture}[node distance=1ex]
  \node (n1) {First};
  \foreach \x in {2,...,6}{%
    \pgfmathparse{int(\x-1)}%
    \node [below = of n\pgfmathresult] (n\x)  {\x};
  }
\end{tikzpicture}
\end{document}

enter image description here

Nodes' position you can determne by defining new counter:

\documentclass[tikz]{standalone}
\usetikzlibrary[positioning]
\begin{document}
\begin{tikzpicture}[node distance=1ex]
  \node (n1) {First};
  \foreach \x [count=\y] in {2,...,6}{%
    \node [below = of n\y] (n\x)  {\x};
  }
\end{tikzpicture}
\end{document}

Result is the same as before.

Zarko
  • 296,517
  • Ah great. That solves the problem, but now I'm still puzzled by why it sort of manages to position nodes below each other, even though the node names are invalid!? – Seamus May 28 '22 at 09:25
  • 1
    The second solution is better because in the first one, \pgfmathresult might be overwritten by \node before it is used. – frougon May 28 '22 at 09:29