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!?

0

4 Answers 4

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}
2
  • 3
    +1. Thank you for nice explanation.
    – Zarko
    May 28, 2022 at 9:44
  • remember is precisely what I want! I was trying to do it myself with \def but that obviously doesn't work. Thanks for the explanation too.
    – Seamus
    May 28, 2022 at 10:10
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

1
  • I knew there must be a smarter way to do this. Thanks for the pointers!
    – Seamus
    May 28, 2022 at 9:35
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}
2
  • Thanks. This is a neat library. It doesn't work for my actual use case, but it's definitely a good solution for some circumstances.
    – Seamus
    May 28, 2022 at 10:09
  • @Seamus My pleasure ^_^ May 28, 2022 at 10:10
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.

2
  • 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, 2022 at 9: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, 2022 at 9:29

Not the answer you're looking for? Browse other questions tagged .