# tikz foreach loops: is there an equivalent of metapost's step?

I apologise if I'm using and searching with incorrect terminology. This seems an obvious question (to me) so I'm surprised I've not found anything (and so assume I'm missing something).

In metapost, I can use the following to define a loop:

for i=some-value step 0.05 until some-other-value:
fill fullcircle scaled so-and-so withcolor i*white;
so-and-so := so-and-so - something;
something-else := i;
endfor;


This means that I can define how large the increments should be without needing to know the initial and final value of i.

Is something similar possible in tikz?

I can achieve the same effect in a more roundabout fashion by calculating the second value for the loop from the first value plus the value of the step. However, I wonder if there is not some simpler method.

That is, the following code works:

\documentclass[border=5pt,tikz]{standalone}

\begin{document}
\tikzset{
/mytree/key1/.initial={-10},
/mytree/key2/.initial={10},
/mytree/step1/.initial={2},
}
\begin{tikzpicture}
\pgfmathsetmacro{\myfirststep}{\pgfkeysvalueof{/mytree/key1} + \pgfkeysvalueof{/mytree/step1}}%
\foreach \i in {\pgfkeysvalueof{/mytree/key1},\myfirststep,...,\pgfkeysvalueof{/mytree/key2}}
\node at (\i,0) {\i};
\end{tikzpicture}
\end{document}


but I wonder is it possible to replace the lines

    \pgfmathsetmacro{\myfirststep}{\pgfkeysvalueof{/mytree/key1} + \pgfkeysvalueof{/mytree/step1}}%
\foreach \i in {\pgfkeysvalueof{/mytree/key1},\myfirststep,...,\pgfkeysvalueof{/mytree/key2}}


with something more elegant such as

    \foreach \i [step=\pgfkeysvalueof{/mytree/step1}] in {\pgfkeysvalueof{/mytree/key1},...,\pgfkeysvalueof{/mytree/key2}}


which would be analogous to the usage of step in metapost?

-
You can embed your customization into a style and use it repeatedly, would that be elegant enough? :P –  percusse Jul 17 '14 at 8:30
@percusse I was hoping for just a step= type option. But if I haven't missed something, then, yes, that would be elegant enough ;). Do you mean literally using .../.style... rather than .../.code...? I'm still somewhat at sea with keys in pgf/tikz! –  cfr Jul 17 '14 at 9:16
Put \pgfkeys{/pgf/foreach/custom step/.code={your first line here doing the computation}} and then use it with \foreach \i[custom step] in {\pgfstuff,\myfirststep,...,\pgfmorestuff}{...} that's what I meant. –  percusse Jul 17 '14 at 9:18
@percusse Aha! I see. I will definitely try this shortly. That does, indeed, look very neat ;). Thanks! –  cfr Jul 17 '14 at 9:23

An implementation with expl3; the complete list is generated, so relieving PGF from the burden of doing the work by itself.

\documentclass{article}
\usepackage{xparse,tikz}

\ExplSyntaxOn
\NewDocumentCommand{\mpfor}{mm}
{% #1 = variable, #2 = keys
\cfr_mpfor:nn { #1 } { #2 }
}

\keys_define:nn { cfr/mpfor }
{
start .fp_set:N = \l_cfr_mpfor_start_fp,
start .value_required:,
end   .fp_set:N = \l_cfr_mpfor_end_fp,
end   .value_required:,
step  .fp_set:N = \l_cfr_mpfor_step_fp,
}

\clist_new:N \l_cfr_mpfor_values_clist

\cs_new_protected:Npn \cfr_mpfor:nn #1 #2
{
\keys_set:nn { cfr/mpfor } { step = 1 , #2 } % default step 1
\bool_do_while:nn
{
(% if the step is positive, continue until <= holds
\fp_compare_p:n { \l_cfr_mpfor_step_fp > \c_zero_fp }
&&
\fp_compare_p:n { \l_cfr_mpfor_start_fp <= \l_cfr_mpfor_end_fp }
)
||
(% if the step is negative, continue until >= holds
\fp_compare_p:n { \l_cfr_mpfor_step_fp < \c_zero_fp }
&&
\fp_compare_p:n { \l_cfr_mpfor_start_fp >= \l_cfr_mpfor_end_fp }
)
}
{
\clist_put_right:Nx \l_cfr_mpfor_values_clist { \fp_eval:n { \l_cfr_mpfor_start_fp } }
}
\cfr_mpfor_foreach:Vn \l_cfr_mpfor_values_clist { #1 }
}

\cs_new_protected:Npn \cfr_mpfor_foreach:nn #1 #2
{
\foreach #2 in ~ { #1 }
}
\cs_generate_variant:Nn \cfr_mpfor_foreach:nn { V }

\ExplSyntaxOff

\begin{document}

\begin{tikzpicture}
\mpfor{\i}{start=-4,step=2,end=8}{\node at (\i,0) {$\i$};}
\end{tikzpicture}

\begin{tikzpicture}
\mpfor{\i}{start=8,step=-2,end=-4}{\node at (\i,0) {$\i$};}
\end{tikzpicture}

\end{document}


Note that no check is performed to see whether the loop ends (it might be added). If the step is zero, only the start point is used.

Any value can be used, so long as it fits in the values accepted by the fp module.

-

This is not really simple method, and not really elegant, but ... is one possibility. This is a TikZ only solution. And it can be adapted to add other keys (like second, random step, exclusive start, exclusive end, ...).

\documentclass[border=5pt,tikz]{standalone}

\pgfkeys{
/stepfor/.cd,
start/.store in={\startvalue},
step/.store in={\stepvalue},
end/.store in={\endvalue}
}
\def\for[#1]#2{
\pgfkeys{/stepfor/.cd,#1}
\pgfmathsetmacro{\secondvalue}{int(\startvalue+\stepvalue)}
\foreach \i in {\startvalue,\secondvalue,...,\endvalue}{#2}
}

\begin{document}
\begin{tikzpicture}
\for[start=-4,step=2,end=8]{\node at (\i,0) {\i};}
\end{tikzpicture}
\end{document}


Note: I have put int in the evaluation of \secondvalue just to make the output nicer ;) But for working with reals it should be deleted, of course.

-

If you accept to use a library outside of TikZ, and you want to loop over integers only, you can take for example xinttools.

Method 1: using xint only.

\documentclass[tikz,border=5pt]{standalone}
\usepackage{xinttools}

\begin{document}
\begin{tikzpicture}
\xintFor* #1 in {\xintSeq[2]{-4}{8}} \do {
\node at (#1,0) {#1};
}
\end{tikzpicture}
\end{document}


Method 2: using xint and \foreach.

\documentclass[tikz,border=5pt]{standalone}
\usepackage{xinttools}

\begin{document}
\begin{tikzpicture}
\edef\interval{\xintListWithSep{,}{\xintSeq[2]{-4}{8}}}
\foreach \i in \interval
\node at (\i,0) {\i};
\end{tikzpicture}
\end{document}


Method 2+: using xint, \foreach and styling.

\documentclass[border=5pt]{standalone}
\usepackage{tikz}
\usepackage{xinttools}
\tikzset{
/pgf/foreach/interval/.code args={from #1 to #2 by #3}{
\edef\interval{\xintListWithSep{,}{\xintSeq[#3]{#1}{#2}}}
}
}
\begin{document}
\begin{tikzpicture}
\foreach[interval=from -4 to 8 by 2] \i in \interval
\node at (\i,0) {\i};
\end{tikzpicture}
\end{document}

-