7

I've just started using TikZ to make basic graphs, and I'm trying to reproduce the Petersen graph. I've managed to make it without using for loops, but this obviously isn't a great method for bigger examples.

Currently, my new code stands at:

\begin{tikzpicture}
\foreach \x in {1,...,5}{
\pgfmathparse{(\x-1)*360/5+90}
\node[draw,circle,inner sep=8pt] (\x) at (\pgfmathresult:120pt) [semithick] {};
}

\foreach \x in {1,...,5}{
\pgfmathparse{(\x-1)*360/5+90}
\node[draw,circle,inner sep=8pt] (5+\x) at (\pgfmathresult:60pt) [semithick] {};
}
\end{tikzpicture}

This works, but isn't complete. However, I've realised that the second set of five nodes aren't numbered as 6, ... , 10 but as 5+1, ... , 5+5, which isn't what I want. I tried using \pgfmathparse{int(5+\x)}\pgfmathresult instead of 5+\x, but this results in an error. Strangely (at least to me), if I put \pgfmathparse{int(5+\x)}\pgfmathresult in the empty braces at the end of the second loop, it'll happily put the numbers 6, ... , 10 in the circles, so I can't see why my method shouldn't work.

What am I doing wrong, and why doesn't it work?

Edit: new code:

\begin{tikzpicture}
\foreach \i[evaluate={\angle=(\i)*360/5+90}] in {0,...,4}
{
    \node[draw,circle,inner sep=8pt] (\i) at (\angle:120pt) [semithick] {};
}
\foreach \i[evaluate={\angle=(\i)*360/5+90}, evaluate={\Name=int(\i+5)}] in {0,...,4}
{
     \node[draw, circle,inner sep=8pt] (\Name) at (\angle:60pt) [semithick] {};
}
\foreach \i in {0,...,4} 
{
    \pgfmathparse{int(mod(\i+1,5))}
    \draw[-] (\i) -- (\pgfmathresult);
}
\foreach \i in {0,...,4} 
{
    \pgfmathparse{int(mod(\i,5)+5)}
    \draw[-] (\i) -- (\pgfmathresult);
}
\foreach \i in {5,...,9} 
{
    \pgfmathparse{int(mod(\i+2,5)+5)}
    \draw[-] (\i) -- (\pgfmathresult);
}
\end{tikzpicture}
0
10

The easiest would be to calculate the names as well as the angle as an option to the \foreach loop.

You also might be interested in the handlers .pgfmath and .pgfmath int as well as the strcat function (and its handler).

The strcat function combines textual input (enclosed in a pair of ") and/or mathematical input together as one “string”. We can use this to create names as suggested in percusseanswer, to build names in the form of n-6, n-7, and so on.

Though, in code 3 I show how you could make your life easier with the chains library and a custom nodes around center style that fully takes care of the positioning.

The lines are drawn in the initial node positioning loop with join on the outer chain and with a single \draw command between the nodes on the chains. The lines between the nodes on the inner chain use a similar loop as in your original code. The final line between the last and the first node on the outer chain is drawn manually.

The macro \numberOfNodes is used so that you do not need to repeat the number 5 (or whatever you want to use) in the code.

References; you can’t (or don’t even need to) use \pgfmath… inside most of the path elements

Code 1

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\foreach \x[evaluate={\angle=(\x-1)*360/5+90}, evaluate={\Name=int(\x+5)}] in {1,...,5}
  \node[draw, circle] (\Name) at (\angle:60pt) {\x};
\end{tikzpicture}
\end{document}

Code 2

\documentclass[tikz]{standalone}
\makeatletter
\pgfkeys{/handlers/.pgfmath/.code=\pgfmathparse{#1}\expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult}}
\pgfkeys{/handlers/.pgfmath int/.code=\pgfmathparse{int(#1)}\expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult}}
\pgfkeys{/handlers/.pgfmath strcat/.code=\pgfmathparse{strcat(#1)}\expandafter\pgfkeys@exp@call\expandafter{\pgfmathresult}}
\pgfmathdeclarefunction{strcat}{...}{%
  \begingroup
    \let\pgfmathresult\pgfutil@empty
    \pgfmathstrcat@@#1\pgfmath@stop}
\def\pgfmathstrcat@@#1{%
  \ifx\pgfmath@stop#1%
    \let\pgfmath@next\pgfmathstrcat@@@
  \else
    \expandafter\def\expandafter\pgfmathresult\expandafter{\pgfmathresult#1}%
    \let\pgfmath@next\pgfmathstrcat@@
  \fi
  \pgfmath@next}
\def\pgfmathstrcat@@@{\pgfmath@smuggleone\pgfmathresult\endgroup}
\makeatother
\begin{document}
\begin{tikzpicture}
\foreach \x[evaluate={\angle=(\x-1)*360/5+90}] in {1,...,5}
  \node[draw, circle, name/.pgfmath strcat={"n-",int(\x+5)}] at (\angle:60pt) {\pgfmathprint{strcat("n-",int(\x+5)}};
\end{tikzpicture}
\end{document}

Code 3

\documentclass[tikz]{standalone}
\usetikzlibrary{chains}
\tikzset{
  nodes around center/.style args={#1:#2:#3:#4}{% #1 = start angle, #2 = number of nodes
                                                % #3 = center,      #4 = distance
    at={(#3)},shift={({(\tikzchaincount-1)*360/(#2)+#1}:{#4})}}}
\begin{document}
\begin{tikzpicture}[
  start chain=inner placed {nodes around center=90:\numberOfNodes:{0,0}:60pt},
  start chain=outer placed {nodes around center=90:\numberOfNodes:{0,0}:120pt}
]
\newcommand*{\numberOfNodes}{5}
\foreach \cnt in {1,...,\numberOfNodes} {
  \node[draw, circle, inner sep=+0pt, minimum size=+20pt, on chain=inner] {};
  \node[draw, circle, inner sep=+0pt, minimum size=+20pt, on chain=outer, join] {};
  \draw (inner-\cnt) -- (outer-\cnt);
}
\foreach \cnt[evaluate={\nextCnt=int(mod(\cnt+2,\numberOfNodes)+1)}] in {1,...,\numberOfNodes}
  \draw (inner-\cnt) -- (inner-\nextCnt);
\draw (outer-end) -- (outer-begin);
\end{tikzpicture}
\end{document}

Output 3

enter image description hereenter image description here

2
  • Thanks, that's really useful. I've included my new code which gives the desired output (and uses a for loop for the edges) but I've used five for loops to achieve this. I couldn't get the loops with evaluate in them to let me do anything else in the loop. Have you any pointers on how to improve it? – lokodiz Sep 12 '13 at 17:58
  • @SimonC Take a look at my updated answer. Firstly, I added a strcat function for PGFmath so that you can easily build a node name that includes a “string” and a calculated part. Secondly, I added a third code that actually builds your diagram but it uses chains (which will build node names like <chain name>-<integer>) and the nodes around center key. We could probably create a chains style similar to nodes around center that also positions the inner nodes like they are connected (skipping every second position) but I don’t want to think about that algorithm. ;) – Qrrbrbirlbel Sep 12 '13 at 21:51
4

You have to use a macro also for the node name. You can't use again \pgfmathparse because the result is saved in the \pgfmathresult macro and it override the other operation you get. So you have to use \pgfmathtruncatemacro to define your own macro.

The circles are not of the same dimension because the texts inside are not of the same dimensions too but I add them only to show you that the nodes have the correct name.

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\foreach \x in {1,...,5}{
\pgfmathparse{(\x-1)*360/5+90}
\node[draw,circle,inner sep=8pt] (\x) at (\pgfmathresult:120pt) [semithick] {};
}

\foreach \x in {1,...,5}{
\pgfmathsetmacro\macroa{(\x-1)*360/5+90}
\pgfmathtruncatemacro\macrob{5+\x}
\node[draw,circle,inner sep=8pt] (\macrob) at (\macroa:60pt) [semithick] {\macrob};
}
\end{tikzpicture}
\end{document}

enter image description here

0
4

Don't use standalone numbers as node names, I can't find the nicest example but it's unnecessary trouble for debugging. Also you won't be able to use the angle anchors e.g. 6.45 is not the upper right anchor. It's just a number. Use something with a letter, say, n-3 etc.

And for simple operations use counters or evaluate expressions.

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

\begin{tikzpicture}
\foreach \x[count=\xi from 6] in {1,...,5}{
\pgfmathparse{(\x-1)*360/5+90}
\node[draw,circle] (n-\xi) at (\pgfmathresult:60pt) [semithick] {\xi};
}
\end{tikzpicture}

\end{document}
2
  • That is not correct, 6.45 still works. There is no , and no : thus a node name (and no intersection and no cs: and no -|/-|). – Qrrbrbirlbel Sep 12 '13 at 15:30
  • @Qrrbrbirlbel I can cook up an example where it is impossible to make it work but the point is not that. Internally there are many places where this trips up. pgfprocess is an angel but not perfect. Basic layer hates such stuff – percusse Sep 12 '13 at 15:32

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.