8

MWE:

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
  \draw (0:2) foreach \a in {30,60,...,330} { -- (\a:2) } -- cycle;
  %\draw foreach \a in {0,30,...,330} { (\a:2) -- } cycle;
\end{tikzpicture}
\end{document}

The first version works, the commented-out second version doesn't (although I think it would be more elegant). What are the rules for what is allowed and what is not when using the foreach path operation? The manual is rather brief at that point.

2
  • 1
    I think that pgf has to pass first the coordinates to get to the other one(s), so simpy -- (…) otherwise it doesn't pass them as mentioned. Cycle is just the first point the path, so just […] -- cycle;. This is actually a really bad answer, but this is just a quick one, so sorry for that … Sep 7, 2018 at 21:52
  • 4
    Each iteration of foreach is a (TeX) group. You can't write \draw {(0,0) --} (0,1); but you can write \draw (0,0) { -- (0,1)};. Sep 9, 2018 at 7:50

3 Answers 3

3

Every foreach statement has to not finish in "--". This is because for some reason tikz uses every of it's foreach speps as a finished statement (in this case).

So, you would not write:

\draw (0:2)--;

because the result would not be good for the compiler and you don't know what you expecting as an output.

The next code demonstrates and almost proves the above:

\documentclass[tikz]{standalone}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
  %\draw (0:2) foreach \a in {30,60,...,330} { -- (\a:2) } -- cycle;
  \begin{scope}
  \draw (0:2)--(30:2)--(60:2)--(90:2)--(120:2);
  \end{scope}
  %Problematic:
  \begin{scope}[shift={(3,0)}]
  \draw (0:2)--;
  \draw (30:2)--;
  \draw (60:2)--;
  \draw (90:2)--;
  \draw (120:2)--;
  \end{scope}

  \begin{scope}[shift={(3,-3)}]
  \draw  foreach \a in {0,30,...,120} {(\a:2)--};% ({\a+30}:2) };%
  \end{scope}
  %Problematic with same result:
  \begin{scope}[shift={(0,-3)}]
  \draw  foreach \a in {0,30,...,90} {(\a:2)--({\a+30}:2) };%
  \end{scope}

  %In your case:
  \begin{scope}[shift={({(3+1.5)/2},-6)}]
  \draw  foreach \a in {0,30,...,330} {(\a:2)--({\a+30}:2) };%
  \end{scope}
\end{tikzpicture}
\end{document}

And the result:

enter image description here

If you see the right pictures, they came of the problematic kind of code that in one case just draws lines finishing in -- and in other case (still left but down) came from the loop ending any of it's statements in --. But the resulting (that of course came with errors in compilation) image is the same like the result of:

 \draw (Point)--;

The solution is just to close every statement's --

5
  • Notice that the OP never has a situation in which something of the sort \draw (Point)--; happens because (s)he has a cycle at the end.
    – user121799
    Sep 7, 2018 at 22:58
  • @marmot I am talking about every step af the foreach in my answer. Sorry, I thought I made that clear. The results above shows that this is the same behavior ...
    – koleygr
    Sep 7, 2018 at 23:14
  • I am sorry, after carefully rereading your answer I cannot see your point. Might well be that this is just me. The fragments in the working part of the question are not complete paths either. At least, the result is not the same as what one would get if one wrote \foreach \a in {30,60,...,330} {\draw (0:2) -- (\a:2) ;}. So it is simply (IMHO) not the case that you need to pass a complete path to the argument of the foreach loop.
    – user121799
    Sep 7, 2018 at 23:28
  • @marmot: The working part does not finish to -- but starting from it and I said "tikz uses every of its statements as a finished statement (in this case)" and I meant for every step of the foreach loop in the case that finish with --. I also don't expect something specific as a result of the non working parts with such tikz errors.
    – koleygr
    Sep 7, 2018 at 23:35
  • Well, this is obvious. I am not the OP but this is IMHO not the answer to the question. The OP pointed out that it does not work, and you are stating the same fact. The question is why it does not work. Of course, if the OP accepts the answer, you'll be fine but IMHO in your answer there is no explanation that goes beyond what the OP and current_user already stated. Maybe you could have a look at this answer, which explains things (rather than repeating observations).
    – user121799
    Sep 7, 2018 at 23:42
2

I've read a bit more, trying to find an explanation in the manual. (I'm referring to version 3.0.1a.)

If you look at the detailed descriptions of the individual operations in chapter 14, you'll see that the syntax always mandates a coordinate at the end. For example, the syntax for the line-to operation is given as --(coordinate or cycle) and in the tutorial section (2.3) it is also said the "-- [...] must be followed by another coordinate". However, the move-to operation is also a valid operation and has the syntax (coordinate).

Later in chapter 83 it says: "TikZ allows you to use foreach [...] inside a path construction. In such a case, the commands must be path construction commands." I think the word commands is a bit misleading here because it is used with a different meaning in other parts of the manual. I guess what is meant here is that the repeated parts inside the curly brackets must be "stand-alone" path operations. This would explain why, say, both -- (\x,\y) and (\x,\y) are OK while (\x,\y) -- isn't.

Anyway, while the TikZ manual is otherwise of super-high quality, I think this tiny part could be a bit more detailed. Also, if I've counted correctly, there are only two examples for foreach inside of path constructions on more than 1,100 pages. A simple example like "this will work and this won't" would probably help.

[This is essentially what @koleygr said, but I wanted to find a clear explanation for this behavior in the manual.]

1
  • 1
    If you look into tikz.code.tex, you'll find % Comment by TT: I hope I fixed the \tikz \foreach problem. The new version will take a conservative approach and will only do fancy stuff when the next keyword after \tikz is one of the following: \draw, \fill, \filldraw, \graph, \matrix,. The next instance of foreach is in \tikz@handle@more, which is the continuation of a very complex set of \if statements. I am aware that this does not answer your question, but I think it suggests that the answer might not be super simple. (+1)
    – user121799
    Sep 8, 2018 at 16:10
2

DISCLAIMER: This is not an answer. Actually, I would be really interested in an answer that explains why that happens.

I quickly glanced through tikz.code.tex and found the comment

Comment by TT: I hope I fixed the \tikz \foreach problem. The new version will take a conservative approach and will only do fancy stuff when the next keyword after \tikz is one of the following: \draw, \fill, \filldraw, \graph, \matrix,

I agree that this does not tell us why the second code example does not work, but one message which one may, or may not, take from this is that foreach is tricky. The reason why I do not agree with koleygr's answer, or the way I read it, is that IMHO it does not explain why this happens, and, what is IMHO even a bit more worrisome, suggests that you need to have a complete path in the second argument of foreach. Of course, since I do not really understand what's going on in detail, I may very well be wrong. Nevertheless I'd like to present a short snippet that does sort of what is intended in the second, nonworking foreach loop. It is a foreach loop that is not too elegant but works.

\documentclass[tikz]{standalone}
\begin{document}
\tikzset{my foreach code/.code={\xdef\Lst{}\foreach #1 }}
\begin{tikzpicture}[]
  \draw [my foreach code={\a in {0,30,...,330} {\xdef\Lst{\Lst (\a:2) -- }}}] 
  \Lst   cycle;
\end{tikzpicture}
\end{document}

enter image description here

It is instructive to compare this to the following nonworking example.

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
  \xdef\Lst{}
  \draw foreach \a in {0,30,...,330} {\xdef\Lst{\Lst (\a:2) -- }} \Lst cycle;
\end{tikzpicture}
\end{document}

One would expect that this works, but it doesn't. According to how I read koleygr's answer, the first code should not work either, but it does. (Those who may want to object that \foreach is not foreach: the pgfmanual states in section 14.14: "For historical reasons, you can also write \foreach instead of foreach.")

BOTTOMLINE: I do not really have a simple message other than this is tricky and it might well be that in the future there might be a foreach version that works with the syntax.

3
  • good thought (+1), use of \foreach is really tricky!
    – Zarko
    Sep 8, 2018 at 23:38
  • @Zarko Thanks! You are much longer around than I. Do you know if foreach has been revised?
    – user121799
    Sep 8, 2018 at 23:44
  • 1
    sorry, i don't know which changes are prepared for new tikz release. for the last few years i no longer monitor complements to tikz, which is preparing for its new version. for compatibility reason years ago i decide to stick only with official version (3.0.1.a).
    – Zarko
    Sep 9, 2018 at 0:04

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.