12

For a document I am working on, I wanted to be able to draw polygon graphs. The graphs are to be labelled with the integers from 0 to n - 1, for some n. I wanted to write a macro that could be called inside a tikzpicture to draw such a graph, when supplied with the number of edges (n) and the "radius" of the graph (distance of each vertex from the centre). It turned out to be quite a frustrating experience because trying to use mathematical expressions involving macro arguments in TikZ's \foreach is not straightforward and results in many baffling error messages, but eventually I realised I just need to use \pgfmathparse to avoid the hassle. Yet I now have a perfectly good graph, except that the edges are "wonky" - each edge seems to connect from one node to a point slightly off the next node. Why is this happening? Here is a screengrab of what I am getting:

Here is a minimal working example.

\documentclass[a4paper]{amsart}

\usepackage{tikz}

\tikzset{graph/.style = {every node/.style = { draw,
                                               shape = circle,
                                               fill = black,
                                               minimum size = 0.8mm,
                                               inner sep = 0mm,
                                               label distance = 0.8mm
                                               }}}

\newcommand{\circumferencenode}[3]{\node (#1) at (#3: #2) [label = #3: $#1$] {};}
\newcommand{\polygon}[2]{
    \pgfmathparse{subtract(#1, 1)}
    \foreach \x in {0, ..., \pgfmathresult} {
        \pgfmathparse{90 - 360 * \x / #1}
        \circumferencenode{\x}{#2}{\pgfmathresult}
    }
    \pgfmathparse{subtract(#1, 1)}
    \foreach \x in {0, ..., \pgfmathresult} {
        \pgfmathparse{mod(\x + 1, #1)}
        \draw (\x) -- (\pgfmathresult);
    }
}

\begin{document}
    \begin{tikzpicture}[graph]
        \polygon{6}{10mm}
    \end{tikzpicture}
\end{document}
12

Your big problem is with \pgfmathparse{mod(\x + 1, #1)}, because the results are 1.0, 2.0... and not 1,2... With (nodename.x), you select a point on the border of node nodename in angle x.

Some advices:

  • Use \pgfmathsetmacro to store the result of a math expression (float) in a macro.
  • Use \pgfmathtruncatemacro to store the result of a math expression (integer) in a macro.
  • Use \typeout to show (and debug) your results.
  • With default math engine, you can't exceed 16383.99999 during calculation, so use {90-360/#1*\x} instead of {90-360*\x/#1}.

So, here is your MWE :

enter image description here

\documentclass{standalone}
\usepackage{tikz}
\tikzset{graph/.style = {every node/.style = { draw,
                                               circle,
                                               fill = black,
                                               minimum size = 0.8mm,
                                               inner sep = 0mm,
                                               }}}

\newcommand{\circumferencenode}[3]{
  \node[label = #3: $#1$] (p#1) at (#3: #2)  {};
}
\newcommand{\polygon}[2]{
    \pgfmathtruncatemacro{\nminusone}{#1 - 1}
    \foreach \x in {0, ..., \nminusone} {
        \pgfmathsetmacro{\angle}{90 - 360 / #1 * \x}
        \circumferencenode{\x}{#2}{\angle}
    }
    \foreach \x in {0,...,\nminusone} {
        \pgfmathtruncatemacro{\next}{mod(\x + 1, #1)}
        \typeout{\next}
        \draw (p\x) -- (p\next);
    }
}

\begin{document}
\begin{tikzpicture}[graph]
  \polygon{6}{10mm}
\end{tikzpicture}
\end{document}
11

There is also the possibility of using directly the library shapes.geometric and the shape regular polygon.

One might proceed as follows:

\documentclass[a4paper]{amsart}

\usepackage{tikz}
\usetikzlibrary{shapes.geometric}

\tikzset{
        new polygon/.code 2 args={
        \node[regular polygon, regular polygon sides=#1, draw,minimum size=1.7cm] (s) {};
        \foreach \corner in {1,...,#1}{
         \pgfmathparse{90-360 * (\corner-1) / #1}
         \node at (\pgfmathresult:#2)[label={[font=\small]\pgfmathresult:$\corner$}]{};
         \node[fill=black,circle, minimum size=0.8mm,inner sep=0mm] at (s.corner \corner){};
        }
    }
}

\begin{document}
\tikz[baseline]\node[new polygon={9}{9mm}] {}; \hspace*{0.5cm}
\tikz[baseline]\node[new polygon={5}{8mm}] {}; \hspace*{0.5cm}
\tikz[baseline]\node[new polygon={11}{7mm}] {};  
\end{document}

The result:

enter image description here

  • Thanks for your advice. I chose Paul's answer because he explained why the graph was incorrect as well as giving a fix, but I appreciate it. – Hammerite Dec 2 '12 at 11:11

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.