3

I am trying to write a command to draw a cycle graph with Tikz, basically a polygon. The parameters of the command are the number #1 of vertices, and the radius #2 of the figure.

My initial thought was to draw the #1 nodes first, give them names and then connect them by an edge. The code was

\newcommand{\cyclegraph}[2]{\begin{tikzpicture}
\foreach \n in {1,...,#1}{
    \node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
}
\foreach \n in {1,...,#1-1}{
    \draw (n\n) -- (n{1+\n})
}   

\draw (n#1) -- (n1);
\end{tikzpicture}}

Unfortunately, the code in the \foreach loop does not work. The error messages are "Package pgf Error: No shape named n{1+1} is known. \cyclegraph{7}{2}", "Package pgf Error: No shape named n{1+2} is known. \cyclegraph{7}{2}", etc. Obviously, that's a problem with the naming of the nodes. Is there a way to fix that?

Of course, I could rewrite the code as

\newcommand{\cyclegraph}[2]{\begin{tikzpicture}
\foreach \n in {1,...,#1}{
    \node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
}
\foreach \n in {1,...,#1-1}{
    \draw ({\n*360/#1}:#2cm) -- ({(1+\n)*360/#1}:#2cm);
}   

\draw ({0}:#2cm) -- ({360/#1}:#2cm);
\end{tikzpicture}}

but I think it would be cleaner to use the names of the nodes. Also, it could be useful for later figures. Any idea?

3
  • 2
    Please always add a complete example, that makes it is much easier to test the problem. Aug 4, 2020 at 8:03
  • @UlrikeFischer: it is the complete command
    – Taladris
    Aug 4, 2020 at 8:15
  • Ok then please copy your post in an empty (!) document and compile it. If you are successfull I will do it too. Aug 4, 2020 at 8:16

3 Answers 3

5

Here is a solution:

\documentclass[tikz]{standalone}
\newcommand{\cyclegraph}[2]{%
  \begin{tikzpicture}
    \foreach \n in {1,...,#1}{
      \node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
    }
    \foreach \n[evaluate={\n as \nnext using int(mod(\n,#1)+1)}] in {1,...,#1}{
      \draw (n\n) -- (n\nnext);
    }   
  \end{tikzpicture}%
}

\begin{document}
\cyclegraph{7}{2}
\end{document}

enter image description here

1
  • Thanks. I was expecting that something simpler existed. Tikz' synthax is confusing.
    – Taladris
    Aug 4, 2020 at 8:26
5

I have code very similar to this. Hacking to fit your use case you can produce:

enter image description here

with the code:

\documentclass{article}
\usepackage{tikz}

\newcommand\CycleGraph[2][1]{%
  \begin{tikzpicture}
    \foreach \pt [evaluate=\pt as \ang using {90+(\pt-1)*360/#2}] in {1,...,#2}
    {
        \node[circle,fill=black] (\pt) at (\ang:#1) {};
    }
    \foreach \pt [remember=\pt as \Pt (initially #2)] in {1,...,#2}
    {
        \draw (\pt)--(\Pt);
    }
  \end{tikzpicture}
}
\begin{document}

  \CycleGraph[0.5]{3}
  \CycleGraph{4}

\end{document}

Notice that I have defined \CycleGraph to have an optional argument that gives the radius of the cycle and a mandatory argument giving the number of points.

Actually, I find the following variation on these ideas to be more useful: I define a command \EdgeGraph to take as arguments the number of vertices together with a comma separated list of edges. For example, \EdgeGraph{4}{1/2,2/3,3/4,4/1} and \EdgeGraph{4}{1/2,2/3,3/4,4/1,1/3} produce:

enter image description here

Here is the code for \EdgeGraph:

\documentclass{article}
\usepackage{tikz}

\newcommand\EdgeGraph[3][1]{%
  \begin{tikzpicture}
      \foreach \pt [evaluate=\pt as \ang using {90+(\pt-1)*360/#2}] in {1,...,#2}
      {
          \node[circle,fill=black] (\pt) at (\ang:#1) {};
      }
      \foreach \x/\y in {#3} {
          \draw (\x)--(\y);
      }
  \end{tikzpicture}%
}
\begin{document}

  \EdgeGraph{4}{1/2, 2/3, 3/4, 4/1}
  \EdgeGraph{4}{1/2, 2/3, 3/4, 4/1, 1/3}

\end{document}

I normally also have options to label the vertices but perhaps I am now getting too carried away!

4

The problem is caused by your second \foreach

\foreach \n in {1,...,#1-1}{
    \draw (n\n) -- (n{1+\n})
}

Firstly, a semicolon is missing. Secondly, calculation is not supported in node names (n{1+\n}). This just gives node names (n{1+1}), (n{1+2}), ... and raises an error.

Apart from more general option evaluate used in @PaulGaborit's answer, here I use another option remember (documented near the end of pgfmanual 3.1.5b, sec. 89) to store the value of \n during the previous iteration in \xn. In the first iteration, there is no "previous one" hence I initialize \xn to 1. I also changed the iteration list to 2, ..., #2.

\documentclass{article}
\usepackage{tikz}

\newcommand{\cyclegraph}[2]{%
  \begin{tikzpicture}
    \foreach \n in {1,...,#1}{
        \node[circle,fill=black] (n\n) at ({\n*360/#1}:#2cm) {};
    }
    \foreach \n[remember=\n as \xn(initially 1)] in {2,...,#1}{
        \draw (n\xn) -- (n\n);
    }
    \draw (n#1) -- (n1);
  \end{tikzpicture}%
}

\begin{document}
  \cyclegraph{3}{2}
\end{document}

Also, posting complete example (also called MWE) rather than complete macro definition is always preferable.

You must log in to answer this question.

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