5

How is it possible to use a declare function in the condition of \foreach? Here's my MWE:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[declare function={a = 0; b = 5;}]
  \foreach \x in {{a},...,{b}}{
    \draw (\x,0) -- (0,\x);
  }
\end{tikzpicture}
\end{document}

This gives me

Missing number, treated as zero.

(line 10, the closing bracket of the loop).

One can even use declared functions in the [options list] of tikzpicture in options coming behind declare function, but why not simply in \foreach?

  • I guess you can’t use it in foreach, because it doesn’t evaluate math at all, sin(2) doesn’t work either, does it? – Tobi Apr 26 '13 at 20:43
  • 1
    As already pointed out by comments and answers, you need to evaluate the values first. Although it is possible to say to evaluate an expression inside the loop using \foreach \x[evaluate=\x] in {…} the loop still uses the un-evaluated values, in this case the loop goes still from a to b and not from 0 to 5. {a, ..., e} would loop over a, b, c, d and e which could be some constants that get evaluated. You can't use it to loop over their values, unfortunately. – Qrrbrbirlbel Apr 26 '13 at 20:56
5

You can evaluate the expression first:

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}[declare function={a=0;b = 5;}]
\pgfmathparse{{a}}\let\pgfmathresulta\pgfmathresult
\pgfmathparse{{b}}\let\pgfmathresultb\pgfmathresult
  \foreach \x in {\pgfmathresulta,...,\pgfmathresultb}{
    \draw (\x,0) -- (0,\x);
  }
\end{tikzpicture}

\end{document}
  • Ah, my question was not detailed enough. I edited it. I actually need two functions in the range. But \pgfmathresult is only one container. – Foo Bar Apr 26 '13 at 20:39
  • In this case you could use \pgfmathsetmacro{<macro>}{<math expression>} and then use <macro> – Tobi Apr 26 '13 at 20:41
  • @FooBar you could just use two macros one for each. I'll update to match – David Carlisle Apr 26 '13 at 20:44
  • @FooBar see update (I kept to the spirit of the original rather that Tobi's version) – David Carlisle Apr 26 '13 at 20:47
  • @Tobi: \pgfmathsetmacro is dangerous and doesn't do what it claims to do. It seems never to be worth using over \pgfmathparse + \let. – Ryan Reich Apr 27 '13 at 4:13
1

This small code adds two keys to the optional \foreach use:

  • use int and
  • use float

I let the example speak for themselves:

\begin{tikzpicture}[declare function={a = 0; b = 5;}]
  \foreach \x[use int=a to b] \draw (\x,0) -- (0,\x);
\end{tikzpicture}

\begin{tikzpicture}
    \foreach \x[use int=2 to 10 step 2] {
        \ifnum\x=\foreachEnd
            \tikzset{every path/.append style=thick}
        \fi
        \draw (\x/2,0) -- (0,\x/3);
    }
\end{tikzpicture}

Disclaimer: No warranties; probably breaks the very next moment.

Code

\documentclass[tikz]{standalone}
\usepackage{tikz}
\makeatletter
\newif\ifqrr@pgf@foreach@no@list
\pgfkeys{
    /pgf/foreach/.cd,
    @use/.code args={#1to#2}{%
        \qrr@pgf@foreach@no@listtrue
        \qrr@pgf@foreach@no@list@use\foreachStart{#1}%
        \pgfutil@in@{step}{#2}
        \ifpgfutil@in@
            \qrr@pgf@foreach@no@list@parse@step#2\pgffor@stop
        \else
            \qrr@pgf@foreach@no@list@parse@step#2step1\pgffor@stop
        \fi
        \edef\qrr@pgf@foreach@no@list@list{\foreachStart,\foreachSecond,...,\foreachEnd}},
    use int/.code={%
        \let\qrr@pgf@foreach@no@list@use\pgfmathtruncatemacro
        \pgfkeysalso{/pgf/foreach/@use={#1}}%
    },
    use float/.code={%
        \let\qrr@pgf@foreach@no@list@use\pgfmathsetmacro
        \pgfkeysalso{/pgf/foreach/@use={#1}}%
    }
}
\def\qrr@pgf@foreach@no@list@parse@step#1step#2\pgffor@stop{%
    \qrr@pgf@foreach@no@list@use\foreachEnd{#1}%
    \qrr@pgf@foreach@no@list@use\foreachSecond{\foreachStart+#2}%
}
\def\pgffor@vars{% manually extended, better etoolbox
    \pgfutil@ifnextchar i{\pgffor@@vars@end}{%
        \pgfutil@ifnextchar[{\pgffor@@vars@opt}{%]
            \pgfutil@ifnextchar/{\pgffor@@vars@slash@gobble}{%
                \ifqrr@pgf@foreach@no@list\expandafter\pgfutil@firstoftwo\else
                    \expandafter\pgfutil@secondoftwo\fi
                {\qrr@pgf@foreach@no@listfalse\pgffor@macro@list\qrr@pgf@foreach@no@list@list}
                {\pgffor@@vars}}}}}%
\makeatother
\begin{document}
\begin{tikzpicture}[declare function={a = 0; b = 5;}]
  \foreach \x[use int=a to b] \draw (\x,0) -- (0,\x);
\end{tikzpicture}

\begin{tikzpicture}
    \foreach \x[use int=2 to 10 step 2] {
        \ifnum\x=\foreachEnd
            \tikzset{every path/.append style=thick}
        \fi
        \draw (\x/2,0) -- (0,\x/3);
    }
\end{tikzpicture}
\end{document}

Output

enter image description here

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.