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.

Say I have a bunch of nodes I've already created in TikZ---maybe v0, v1, ..., vn-1. I'd like to connect certain of these nodes in a systematic way, by doing arithmetic on the indices, ideally mod n. For example, something like

\foreach \i \in {0,1,...,n-1} {\draw[->] (v\i) -- (v\{i+2})} But that doesn't work, and I can't seem to figure out the right syntax. And when I try to do complicated things with \pgfmathmod to do do the modular arithmetic on the node names, instead of the arrows connecting nicely between the nodes, I get the arrow connecting across the node to an inappropriate edge.

When I try something like \foreach \i / \j in {0 / 2, ..., n-2 / n}{ (v\i) -- (v\j)} I get a strange error message "no node named v0" (or something like that).

Any suggestions? This seems like a rather obvious thing to want to be able to do.

share|improve this question
add comment

4 Answers 4

up vote 19 down vote accepted

The let command is useful here and allows for "inline computation":

\begin{tikzpicture}
  \foreach \i in {0,...,9} \draw (\i*36:2cm) node(\i){\i};
  \foreach \i in {0,...,9} \draw let \n1={int(mod(\i+2,10))} in (\i) -- (\n1);
\end{tikzpicture}

the result

share|improve this answer
3  
Very nice! I wasn't aware of the let command. I now need to go back and rewrite all my horrible code to use that! –  Loop Space Oct 18 '10 at 18:46
    
That's beautiful. Thank you very much---this was making me totally crazy. Only, when I try to compile it, first I got an error saying I needed to include \usetikzlibrary{calc}. Ok, so I did that. Now I'm getting an error saying that ` ! Package PGF Math Error: Unknown function `int'. –  Leah Wrenn Berman Oct 18 '10 at 19:54
    
Ok, I don't know why int doesn't work: I thought it was because I didn't have PGF 2.0 installed, but that appears not to be the case. If I replace it with floor (to try to force an int), the arrows don't connect nicely to the nodes, but rather connect to the theta=0 part of a circle, which looks ugly and causes arrows to cross over the nodes. –  Leah Wrenn Berman Oct 20 '10 at 17:59
2  
That's because floor leads to <node number>.0 instead <node number>. Adding ".0" means the same as connect to "<node number>.E". It is an anchor and every number between 0 and 360 leads to an obvious result. –  Christian Oct 20 '10 at 18:11
add comment

You can use the \pgfmathparse macro to do this. It's documented in the (amazing) TikZ and PGF manual, in Part VII, but all you need to know right now is this: \pgfmathparse{...} evaluates the mathematical expression that is ... and stores the result in \pgfmathresult. The ... should look something like 3 + 4 * 5 - sin(6). I don't know that there's a better syntax for this, but if you use it to effectively declare variable up front (e.g., \pgfmathparse{...}\let\j\pgfmathresult), it's not bad.

Before I get to sample code, two other remarks. First, the reason the second case fails is that, as far as I understand, you can only use the ... in the one-variable case. Secondly, the first case—with \{i+2}—is sufficiently wrong that I feel it's worth pointing it out. On the one hand, \i is is a macro which expands to some value: first 0, then 1, and so on. On the other hand, i is a character which, when typeset, produces "i". There is no connection between the two. Thus, when you write \{i+2}, you're looking at five tokens: \{, i, +, 2, and }. The first one represents {, the second three represent themselves, and the last one will try to end the group after \foreach.

Anyway, using \pgfmathparse, we can get something like this:

\documentclass{article}

\usepackage{tikz}

\begin{document}
  \begin{center}\begin{tikzpicture}
    \foreach \i in {0,1,...,5} {
      \pgfmathparse{60*\i}
      \node[draw] (v\i) at (\pgfmathresult:2) {\i} ; % Polar coordinates
    }

    \foreach \i in {0,1,...,5} {
      \pgfmathparse{mod(\i+2,6)}
      \draw[->] (v\i) -- (v\pgfmathresult) ;
    }
  \end{tikzpicture}\end{center}
\end{document}

The first \foreach writes out the nodes in polar coordinates (which are (angle:radius)); the second one connects them as you desired.

share|improve this answer
    
Snap! (And I keep forgetting about polar coordinates - much better than using scope environments to rotate the picture) –  Loop Space Oct 18 '10 at 18:21
    
Yeah, I knew the scary bracing in v{\i+2} was bad, but I couldn't figure out how to fix the obviously bad v\i+2, either. This is very helpful---thanks! –  Leah Wrenn Berman Oct 18 '10 at 19:54
1  
FYI, if you try this, it gives the arrows to the right vertices, but the placement of the arrows is ugly (some arrows cross nodes, they're connecting to the edge of the node, etc.). I'd actually gotten something roughly like this, but figured I was doing something wrong because the output wasn't looking right. –  Leah Wrenn Berman Oct 18 '10 at 20:02
add comment

If int is not working, it may be because you need to upgrade your packages.

However, a solution that does not require int is to use the \pgfmathtruncatemacro macro. For example,

\begin{tikzpicture}
  \foreach \i in {0,...,9} 
  {
      \draw (\i*36:2cm) node(v\i){v\i};
  }

\foreach \i in {0,...,9} 
{
    \pgfmathtruncatemacro{\j}{mod(\i+2,10)} 
    \draw [->] (v\i) -- (v\j);
}
\end{tikzpicture} 
share|improve this answer
add comment

I suspect that the problem actually lies with the ... bit in the \foreach list definition. I guess it's a bit tricky to work out how to fill in the dots on a double list. One could argue that this case is simple enough that it ought to "just work", but I guess that it would very quickly get complicated.

Anyway, why is perhaps less important than how to achieve the same result. I've been doing something a bit like this myself recently and here's how I did it:

\documentclass{article}

\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\foreach \i in {0,...,8} {
  \begin{scope}[rotate=\i * 40]
  \node (v\i) at (0,2) {\i};
  \end{scope}
}
\foreach \i in {0,...,8}{
  \pgfmathparse{int(Mod(\i + 2,9))}
  \edef\j{\pgfmathresult}
  \draw[->] (v\i) -- (v\j);
}
\end{tikzpicture}
\end{document}

which produces:

alt text

One important point: I found that \pgfmathsetmacro{\j}{int(Mod(\i + 2, 9))} would set \j to, say, 1.0 which wasn't what was wanted. However, using int meant that \pgfmathresult correctly stored the integer so a simple \edef\j{\pgfmathresult} stored that (the int is to convert the result of Mod - a decimal - to an integer).

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.