Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I try to use nested \foreach loops to create edges between many nodes.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
  \node (a) at (0, 1) {};
  \node (b) at (0, -1) {};
  \node (c) at (1, 0) {};
  \node (d) at (-1, 0) {};
  \foreach \from/\targets in {%
    b/d,%
    {a/b,c,d}%
  } {
    \typeout{\from-\targets}
    \foreach \to in {\targets} {
      \typeout{ \from-\to}
      \path (\from) edge (\to);
    }
  }
\end{tikzpicture}
\end{document}

But this fails with the cryptic error

b-d
 b-d
a-b,c,d
 a-b,c,d

! Package PGF Math Error: Unknown function `b' (in 'b').

As \typeout visible before the error show, seemingly \targets is not expanded and thus interpreted a single parameter instead of a list. Can expansion be forced at this point? Or is there another way to fix it?

share|improve this question
    
Since you have some responses below that seem to answer your question, please consider marking one of them as ‘Accepted’ by clicking on the tickmark below their vote count (see How do you accept an answer?). This shows which answer helped you most, and it assigns reputation points to the author of the answer (and to you!). It's part of this site's idea to identify good questions and answers through upvotes and acceptance of answers. –  Jubobs Dec 10 '13 at 10:04
add comment

3 Answers

You need to remove the parentheses from the inner loop. Namely, instead of passing {\targets} to the \foreach loop, you should be passing \targets.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\begin{tikzpicture}
  \node (a) at (0, 1) {};
  \node (b) at (0, -1) {};
  \node (c) at (1, 0) {};
  \node (d) at (-1, 0) {};
  \foreach \from/\targets in {%
    b/d,%
    {a/b,c,d}%
  } {
    \typeout{\from-\targets}
    \foreach \to in \targets {
      \typeout{ \from-\to}
      \path (\from) edge (\to);
    }
  }
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
Or \foreach \from/\targets in {b/{d},a/{b,c,d}}... –  Jubobs Dec 8 '13 at 18:13
    
@Jubobs which--what you suggest--is much easier to read and understand. :) I was just trying to stick with the OP's notation. –  A.Ellett Dec 8 '13 at 18:14
    
I couldn't make sense of the OP's notation, so I took some liberties :) –  Jubobs Dec 8 '13 at 18:16
add comment

Problems with \foreach aside, I think the syntax

\path (b) edge (d)
      (a) edge (b) edge (c) edge (d);

comes much more natural. It is also much easier to change edge options on an edge-to-edge basis (or for more than one edge, too):

\path (b) edge (d) {[thick]
      (a) edge (b) edge[green] (c) edge[red,->] (d)};

Though, a similar thing can still be done with \foreach, say

\path (b) edge (d) {[thick]
      (a) \foreach \opt/\p in {/b, green/c, {red,->}/d}
                  {edge[style/.expand once=\opt] (\p)}};

With my qrr.misc library (code similar to the keys in another answer of mine), one can do

\path (b) edge (d) {[thick]
      (a) [edges to={b,[green] c, [{red,->}] d}]};

It should be noted that the , in the options has to be protected somehow, either in that way shown or by doing {[red, ->] d}, i.e. enclosing the whole thing in braces. (This could be made more robust or can be changed to use ( and ) around the coordinates instead of using ,, but the implementation will need more parsing then.)

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{qrr.misc}
\begin{document}
\begin{tikzpicture}
  \node (a) at (0, 1) {};  \node (b) at (0, -1) {};
  \node (c) at (1, 0) {};  \node (d) at (-1, 0) {};
  \path (b) edge (d) {[thick]
        (a) edge (b) edge[green] (c) edge[red,->] (d)};
\end{tikzpicture}
\begin{tikzpicture}
  \node (a) at (0, 1) {};  \node (b) at (0, -1) {};
  \node (c) at (1, 0) {};  \node (d) at (-1, 0) {};
  \path (b) edge (d) {[thick]
        (a) \foreach \opt/\p in {/b, green/c, {red,->}/d}
                    {edge[style/.expand once=\opt] (\p)}};
\end{tikzpicture}
\begin{tikzpicture}
  \node (a) at (0, 1) {};  \node (b) at (0, -1) {};
  \node (c) at (1, 0) {};  \node (d) at (-1, 0) {};
  \path (b) edge (d) {[thick]
        (a) [edges to={b,[green] c, [{red,->}] d}]};
\end{tikzpicture}
\end{document}

Output

enter image description here

share|improve this answer
add comment

The important thing is to be consistent in the way you specify elements in a list to be processed by \foreach.

In the approach below, which I find more intuitive, \targets gets expanded to {b} at the first iteration of the outer loop, and to {b,c,d} at the second one. Therefore, specifying \foreach \to in \targets for the inner loop works as expected.

enter image description here

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
  \node (a) at (0, 1) {};
  \node (b) at (0, -1) {};
  \node (c) at (1, 0) {};
  \node (d) at (-1, 0) {};
  \foreach \from/\targets in {b/{d},a/{b,c,d}}
  {%
    \typeout{\from-\targets}
    \foreach \to in \targets
    {%
        \typeout{ \from-\to}
      \path (\from) edge (\to);
    }
  }
\end{tikzpicture}
\end{document}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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