First index is not integer using foreach loop from 0
You could just tell TikZ explicitly that you want an integer.
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}
\tikzset{mynode/.style={circle, fill=blue!25, minimum size=0.1 cm}}
\foreach \ilayer in {0,...,3} {
\tikzmath {\nnodes = 3 ^ \ilayer; }
\tikzmath {\leftnum = int(1 - floor(\nnodes / 2) - 1); }
\tikzmath {\rightnum = \nnodes - floor(\nnodes / 2) - 1; }
\foreach \isibling in {\leftnum,...,\rightnum} {
\tikzmath {\d = 3 ^ (- \ilayer) * 15; }
\tikzmath {\x = \isibling * \d; }
\tikzmath {\y = - \ilayer * 2; }
\node[mynode] (node_\ilayer_\isibling) at (\x cm, \y cm) {\isibling};
}
}
\end{tikzpicture}
\end{document}
Or
\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}
\tikzset{mynode/.style={circle, fill=blue!25, minimum size=0.1 cm}}
\foreach \ilayer in {0,...,3} {
\tikzmath {int \nnodes,\leftnum,\rightnum;
\nnodes = 3 ^ \ilayer;
\leftnum = 1 - floor(\nnodes / 2) - 1;
\rightnum = \nnodes - floor(\nnodes / 2) - 1; }
\foreach \isibling in {\leftnum,...,\rightnum} {
\tikzmath {\d = 3 ^ (- \ilayer) * 15;
\x = \isibling * \d;
\y = - \ilayer * 2; }
\node[mynode] (node_\ilayer_\isibling) at (\x cm, \y cm) {\isibling};
}
}
\end{tikzpicture}
\end{document}
In principle you do not need the math library here.
\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\begin{tikzpicture}
\tikzset{mynode/.style={circle, fill=blue!25, minimum size=0.1 cm}}
\foreach \ilayer [evaluate=\ilayer as \nnodes using {int(3 ^ \ilayer)},
evaluate=\nnodes as \leftnum using {int(1 - floor(\nnodes / 2) - 1)},
evaluate=\nnodes as \rightnum using {int(\nnodes - floor(\nnodes / 2) - 1)}]
in {0,...,3} {
\foreach \isibling
[evaluate=\ilayer as \d using {3 ^ (- \ilayer) * 15},
evaluate=\isibling as \x using {\isibling * \d},
evaluate=\ilayer as \y using {- \ilayer * 2}]
in {\leftnum,...,\rightnum} {
\node[mynode] (node_\ilayer_\isibling) at (\x cm, \y cm)
{\isibling};
}
}
\end{tikzpicture}
\end{document}
As @marmot said you do not need tikzmath
here, but if you use it you can do it in more efficient way :
- You can have a single
\tikzmath
command with loops inside it. - You can declare your integer variables as
int
so you do not need to doint()
afterward. - As
\nnodes
is odd you do not need separate\rightnum
and\leftnum
as\rightnum = - \leftnum
; - Why you use
1-floor(\nnodes/2)-1
in place of-floor(\nnodes/2)
? - The value
\d
can be calculated in the outer loop. - Instead of using
\x=\isibling*\d
you can say[x=\d cm]
and then use\isibling
as\x
. And in the same way\y
can be replaced by\ilayer
using[y=-2cm]
.
So here is my proposal :
\documentclass[tikz,border=7pt]{standalone}
\usetikzlibrary{math}
\begin{document}
\begin{tikzpicture}
\tikzstyle{node}=[circle, fill=blue!25, minimum size=0.1 cm];
\tikzmath{
int \ilayer,\nnodes,\rightnum,\isibling;
\nnodes = 1;
for \ilayer in {0,...,3}{
\rightnum = (\nnodes-1)/2;
\d = 15/\nnodes;
for \isibling in {-\rightnum,...,\rightnum}{
{
\path[x=\d cm,y=-2cm]
node[node] (node_\ilayer_\isibling) at (\isibling, \ilayer) {\isibling};
};
};
\nnodes = 3*\nnodes;
};
}
\end{tikzpicture}
\end{document}