Seeking help in simplifying a TikZ Tonnetz
Instead of nesting loops unnecessarily, I make a test in a single loop on the number of nodes to display (7; 8; 7 and 8 per line).
%LuaLaTeX
\documentclass[tikz,border=5mm]{standalone}
%\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[xscale=1.5,yscale=2.5981]
\footnotesize
\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,0.5) rectangle (\columns,\rows);
%\foreach \x in {0,0.5,1,...,\columns}
\foreach \y in {0,0.5,1,...,\rows}
\foreach \z in {-1.5,-0.5,...,\columns}
{
\draw (0,\y) -- (\columns,\y);
\draw (\z,\rows) -- (\z+2,0);
\draw (\z,0) -- (\z+2,\rows);
}
\end{scope}
\draw[fill=gray!50] (3.5,1) -- (4.5,1) -- (4,1.5) -- cycle;
\foreach \row/\x [count=\n]in {E/0.5,B/1.5,F$\sharp$/2.5,C$\sharp$/3.5,G$\sharp$/4.5,D$\sharp$/5.5,A$\sharp$/6.5,C/0,G/1,D/2,A/3,E/4,B/5,F$\sharp$/6,C$\sharp$/7,E$\flat$/0.5,B$\flat$/1.5,F/2.5,C/3.5,G/4.5,D/5.5,A/6.5,C$\flat$/0,G$\flat$/1,D$\flat$/2,A$\flat$/3,E$\flat$/4,B$\flat$/5,F/6,C/7}
%\foreach \bottomrow/\bottomx in {E$\flat\flat$/0.5,B$\flat\flat$/1.5,F$\flat$/2.5,C$\flat$/3.5,G$\flat$/4.5,D$\flat$/5.5,A$\flat$/6.5}
{
\ifnum \n < 8
\node[draw,circle,minimum size=0.75cm,fill=white] at (\x,2) {\row};
\else
\ifnum \n <16
\node[draw,circle,minimum size=0.75cm,fill=white] at (\x,1.5) {\row};
\else
\ifnum \n <23
\node[draw,circle,minimum size=0.75cm,fill=white] at (\x,1) {\strut \row};
\else
\node[draw,circle,minimum size=0.75cm,fill=white] at (\x,0.5) {\strut \row};
\fi
\fi
\fi
%\node[draw,circle,minimum size=0.75cm,fill=white] at (\bottomx,0) {\strut \bottomrow};
}
\end{tikzpicture}
As mentioned previously, your problem is that you're doing the same thing many times, because you're nesting the loops. Take the loops drawing the grid. The drawing instructions in the innermost loop (over \z
) is repeated for each iteration of that loop. But the entire loop is again repeated for each iteration of the second loop (over \y
). And that loop is repeated for each iteration of the outermost loop (over \x
). As a result, because there are 10 steps in the x-loop and 14 steps in the z-loop, you're drawing every horizontal line 140 times.
The same thing happens for the nodes. Each consecutive loop is repeated for every iteration of the loop it's placed within, so when you get five levels deep, with 7 or 8 iterations in each level, you end up drawing each node over 3000 times.
For the grid, you could do this:
\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,-\pgflinewidth) rectangle (\columns,\rows);
\foreach \y in {0,0.5,1,...,\rows}
\draw (0,\y) -- (\columns,\y);
%the previous loop has ended, start a new:
\foreach \z in {-1.5,-0.5,...,\columns}
{
\draw (\z,\rows) -- (\z+2,0);
\draw (\z,0) -- (\z+2,\rows);
}
\end{scope}
The horizontal lines are drawn in one loop, the diagonal lines in a separate loop.
For the nodes you can do the same thing, have one loop for each line:
\foreach \toprow [count=\topx] in {E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}
\node[note] at (\topx-0.5,2) {\toprow};
\foreach \secondrow [count=\secondx from 0] in {C,G,D,A,E,B,F$\sharp$,C$\sharp$}
\node[note] at (\secondx,1.5) {\secondrow};
\foreach \thirdrow[count=\thirdx] in {E$\flat$,B$\flat$,F,C,G,D,A}
\node[note] at (\thirdx-0.5,1) {\strut \thirdrow};
\foreach \fourthrow[count=\fourthx from 0] in {C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C}
\node[note] at (\fourthx,0.5) {\strut \fourthrow};
\foreach \bottomrow[count=\bottomx] in {E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$}
\node[note] at (\bottomx-0.5,0) {\strut \bottomrow};
I.e. instead of having foreach x (foreach y (foreach z <do stuff x y and z> ) )
, you have foreach x <do stuff x>
, then foreach y <do stuff y>
etc.
Above I made use of the count
feature of \foreach
, that way you don't have to fiddle around with the a/b
syntax. You could also iterate over a list of lists:
\foreach \notelist [count=\row from 0] in {
{E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$},
{C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C},
{E$\flat$,B$\flat$,F,C,G,D,A},
{C,G,D,A,E,B,F$\sharp$,C$\sharp$},
{E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}}
\foreach \note [count=\column from 0,evaluate={\colX=\column+0.5-mod(\row,2)/2;}] in \notelist
\node [note] at (\colX,\row*0.5) {\strut \note};
There are some simple calculations to get the coordinates correct.
Complete code, containing both variants for the nodes:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[
xscale=1.5,yscale=2.5981,
note/.style={draw,circle,minimum size=0.75cm,fill=white},
every node/.append style={font=\footnotesize}
]
%\footnotesize
\begin{scope}
\newcommand*\columns{7}
\newcommand*\rows{2}
\clip(0,-\pgflinewidth) rectangle (\columns,\rows);
\foreach \y in {0,0.5,1,...,\rows}
\draw (0,\y) -- (\columns,\y);
\foreach \z in {-1.5,-0.5,...,\columns}
{
\draw (\z,\rows) -- (\z+2,0);
\draw (\z,0) -- (\z+2,\rows);
}
\end{scope}
\draw[fill=gray!50] (3.5,1) -- (4.5,1) -- (4,1.5) -- cycle;
%\foreach \toprow [count=\topx] in {E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}
% \node[note] at (\topx-0.5,2) {\toprow};
%
%\foreach \secondrow [count=\secondx from 0] in {C,G,D,A,E,B,F$\sharp$,C$\sharp$}
% \node[note] at (\secondx,1.5) {\secondrow};
%
%\foreach \thirdrow[count=\thirdx] in {E$\flat$,B$\flat$,F,C,G,D,A}
% \node[note] at (\thirdx-0.5,1) {\strut \thirdrow};
%
%\foreach \fourthrow[count=\fourthx from 0] in {C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C}
% \node[note] at (\fourthx,0.5) {\strut \fourthrow};
%
%\foreach \bottomrow[count=\bottomx] in {E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$}
% \node[note] at (\bottomx-0.5,0) {\strut \bottomrow};
\foreach [count=\row from 0] \notelist in {
{E$\flat\flat$,B$\flat\flat$,F$\flat$,C$\flat$,G$\flat$,D$\flat$,A$\flat$},
{C$\flat$,G$\flat$,D$\flat$,A$\flat$,E$\flat$,B$\flat$,F,C},
{E$\flat$,B$\flat$,F,C,G,D,A},
{C,G,D,A,E,B,F$\sharp$,C$\sharp$},
{E,B,F$\sharp$,C$\sharp$,G$\sharp$,D$\sharp$,A$\sharp$}}
\foreach \note [count=\column from 0,evaluate={\colX=\column+0.5-mod(\row,2)/2;}] in \notelist
\node [note] at (\colX,\row*0.5) {\strut \note};
\end{tikzpicture}
\end{document}