6

I'm trying to use styles to generate TikZ figures that have repeated, regularly spaced elements by looping through an array, but am perplexed by the results I'm getting.

For example, if I define the style

state/.style={circle,draw=none,inner sep=0pt,minimum size=7mm,label=center:$#1$,name=#1}

then when I try to iterate through an array as the source of the arguments to the style, as in

\def\labels{{e,a,a^2,a^3}};\def\dim{4};
\foreach \n in {0,1,2,3} {
    \node[state={\labels[\n]}]at({cos(90+\n*(360/\dim))},{sin(90+\n*(360/\dim))}){};}

I get an error: Package pgf Error: No shape named e is known.

If I change around the definition of the array and the iterator(s)a bit,

\def\nodes{0/{e},1/{a},2/{a^2},3/{a^3}};\def\dim{4};
\foreach \n\lab in \nodes{
    \node[state={\lab}]at({cos(90+\n*(360/\dim))},{sin(90+\n*(360/\dim))}){};}

I can get the result I want (see MWE), but I'd rather not do this, as it requires an array structure that's not generally useable for my purposes.

enter image description here

How can I get the first form of the iterator and array to work?


\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{positioning}
\usetikzlibrary{arrows}
\usetikzlibrary{petri}

\begin{document}

\tikzset{
    redarrow/.style={->, red, fill=none,>=stealth, thick},
    state/.style={circle,draw=gray,inner sep=0pt,minimum size=7mm,label=center:$#1$,name=#1}}

\begin{center}

\begin{tikzpicture}
% This approach results in an error
% \def\labels{{e,a,a^2,a^3}};\def\dim{4};
% \foreach \n in {0,1,2,3} {
%   \node[state={\labels[\n]}]at({cos(90+\n*(360/\dim))},{sin(90+\n*(360/\dim))}){};}
\def\nodes{0/{e},1/{a},2/{a^2},3/{a^3}};\def\dim{4};
\foreach \n\lab in \nodes{
    \node[state={\lab}]at({cos(90+\n*(360/\dim))},{sin(90+\n*(360/\dim))}){};}
\draw[redarrow](e)--(a);\draw[redarrow](a)--(a^2);\draw[redarrow](a^2)--(a^3);\draw[redarrow](a^3)--(e);
\end{tikzpicture}

\end{center}

\end{document}
1
  • Another version of this scenario produces an odd result: if I change the order of the approaches above, I no longer get the error, but instead get a figure that "uses" the elements defined in the first figure, and gives them labels like "e,a,a^2,a^3[0]".
    – orome
    May 21, 2012 at 20:16

1 Answer 1

6

Update

Sorry I did not know that pgfmath could work with arrays. The problem is that you need to use "e", "a" etc.. because "pgfmath" replaces e by 2.71828, and says that a is not a math function.

Don't forgot the next two rules.

Each element in the array will be evaluated as it is parsed, so expressions can be used.

and

"x" (group operators) These operators are used to quote x. However, as every expression is expanded with \edef before it is parsed, macros (e.g., font commands like \tt or \Huge) may need to be “protected” from this expansion (e.g., \noexpand\Huge). Ideally, you should avoid such macros anyway. Obviously, these operators should be used with great care as further calculations are unlikely to be possible with the result.

A solution is the next code but I don't like the node's names perhaps simpler is to use \n for the names.

remark : the result of \pgfmathparse{\labels[\n]} is given by \pgfmathresult and it's possible in some cases, to store this result with another macro.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows}

\begin{document}

\tikzset{
    redarrow/.style 2 args={->, red, fill=none,>=stealth, thick},
    state/.style={circle,draw=gray,inner sep=0pt,minimum size=7mm,label=center:#1}}

\begin{center}

\begin{tikzpicture}
 \def\dim{4}
\def\labels{{"e","a","a^2","a^3"}}
\foreach \n in  {0,...,3}{
\pgfmathparse{\labels[\n]} 
\node[state={$\pgfmathresult$}] (\pgfmathresult) at ({cos(90+\n*(360/\dim))},{sin(90+\n*(360/\dim))}){};
  }   

\draw[redarrow](e)--(a);\draw[redarrow](a)--(a^2);\draw[redarrow](a^2)--(a^3);\draw[redarrow](a^3)--(e);
\end{tikzpicture}

\end{center}

\end{document} 

also possible is

\tikzset{
    redarrow/.style 2 args={->, red, fill=none,>=stealth, thick},
    state/.style={circle,draw=gray,inner sep=0pt,minimum size=7mm,label=center:$#1$,name=#1}}

\begin{tikzpicture}
 \def\dim{4}
\def\labels{{"e","a","a^2","a^3"}}
\foreach \n in  {0,...,3}{
\pgfmathparse{\labels[\n]} 
\node[state={\pgfmathresult}]  at ({cos(90+\n*(360/\dim))},{sin(90+\n*(360/\dim))}){};
  }   
\draw[redarrow](e)--(a);\draw[redarrow](a)--(a^2);\draw[redarrow](a^2)--(a^3);\draw[redarrow](a^3)--(e);
\end{tikzpicture} 

enter image description here


First answer :

\documentclass{article}
\usepackage{tikz}


\begin{document}

\tikzset{state/.style={circle,
                       draw=gray,
                       inner sep=0pt,
                       minimum size=7mm,
                       label=center:$#1$,
                       name=#1}}

\begin{center}
\begin{tikzpicture}

\def\labels{e,a,a^2,a^3}\def\dim{4}
\foreach \n [count=\ni] in \labels {% 
  \node[state={\n}] at ({cos(90+\ni*(360/\dim))},{sin(90+\ni*(360/\dim))}){};}  

\end{tikzpicture}

\end{center}
\end{document} 
3
  • I was building from the example on the top of p.529 of the TikZ-PGF manual (v. 2.10). Where did I go wrong in adapting that?
    – orome
    May 21, 2012 at 22:19
  • 1
    Ha ! there is an array structure inside pgfmath. I think you need to access values of the array with pgfmathparse. I will update my answer. May 22, 2012 at 6:01
  • Thanks. And thanks for keeping the old answer too for reference. That was also quite helpful.
    – orome
    May 22, 2012 at 13:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .