[Tex/LaTex] Draw nodes with path in tikz

tikz-pgf

How can I draw a path of nodes forming a circle with tikz?

I have tried placing the nodes manually with

\documentclass[tikz]{standalone}

\usetikzlibrary{arrows,positioning}

\begin{document}
\begin{tikzpicture}[->,node distance=2cm, auto, thick,main node/.style={circle,fill=blue!20,draw}]

  \node[main node] (1) {A};
  \node[main node] (2) [above left=of 1] {B};
  \node[main node] (3) [above right=of 1] {C};
  \node[main node] (4) [above=of 2] {D};
  \node[main node] (5) [above=of 3] {E};

  \path[draw, every node/.style={font=\sffamily\small}] (1) -- (2) -- (4) -- (5) -- (3) -- cycle;
\end{tikzpicture}
\end{document}

but it's very difficult to organize them properly. I think it is easily to do with only 4 nodes but I need 5 nodes. I wonder if I can draw the nodes with a path.

Edit

Sorry, I forgot to tell that I need arrows between the nodes and I want different texts in each node.

Can I still use a foreach? I can perhaps make a list of the texts and let the foreach determine which element in the list to draw?

Best Answer

Nodes on a regular polygon

It is possible to put circular nodes with various sizes on a circle and corners of a regular polygon and draw arrows between them, which are also on the circle.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{bending}

\begin{document}
\begin{tikzpicture}[
  ->,   
  thick,
  main node/.style={circle, fill=blue!20, draw},
]
  \newcommand*{\MainNum}{5}
  \newcommand*{\MainRadius}{1.5cm} 
  \newcommand*{\MainStartAngle}{90}

  % Print main nodes, node names: p1, p2, ...
  \path
    (0, 0) coordinate (M)
    \foreach \t [count=\i] in {A, Hello\\World, 3, foobar, $\cdot$} {
      +({\i-1)*360/\MainNum + \MainStartAngle}:\MainRadius)
      node[main node, align=center] (p\i) {\t}
    }
  ;  

  % Calculate the angle between the equal sides of the triangle
  % with side length \MainRadius, \MainRadius and radius of circle node
  % Result is stored in \p1-angle, \p2-angle, ...
  \foreach \i in {1, ..., \MainNum} {
    \pgfextracty{\dimen0 }{\pgfpointanchor{p\i}{north}} 
    \pgfextracty{\dimen2 }{\pgfpointanchor{p\i}{center}}
    \dimen0=\dimexpr\dimen2 - \dimen0\relax 
    \ifdim\dimen0<0pt \dimen0 = -\dimen0 \fi
    \pgfmathparse{2*asin(\the\dimen0/\MainRadius/2)}
    \global\expandafter\let\csname p\i-angle\endcsname\pgfmathresult
  }

  % Draw the arrow arcs
  \foreach \i [evaluate=\i as \nexti using {int(mod(\i, \MainNum)+1}]
  in {1, ..., \MainNum} {  
    \pgfmathsetmacro\StartAngle{   
      (\i-1)*360/\MainNum + \MainStartAngle
      + \csname p\i-angle\endcsname
    }
    \pgfmathsetmacro\EndAngle{
      (\nexti-1)*360/\MainNum + \MainStartAngle
      - \csname p\nexti-angle\endcsname
    }
    \ifdim\EndAngle pt < \StartAngle pt
      \pgfmathsetmacro\EndAngle{\EndAngle + 360}
    \fi
    \draw
      (M) ++(\StartAngle:\MainRadius)
      arc[start angle=\StartAngle, end angle=\EndAngle, radius=\MainRadius]
    ;
  }
\end{tikzpicture}
\end{document}

Result

Equidistant nodes

Instead of putting the nodes on the corners of a regular polygon, the nodes can be placed in such a way on the circle, that the arrows have equal lengths. The advantage is, that the main radius can be made smaller for a more compact presentation.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{bending}

\begin{document}
\begin{tikzpicture}[
  ->,
  thick,
  main node/.style={circle, fill=blue!20, draw, align=center},
]
  \newcommand*{\MainRadius}{1.2cm}
  \newcommand*{\MainStartAngle}{90}

  \coordinate (M) at (0, 0);

  \newcommand*{\MainAngleSum}{0}
  \begin{scope}
    % First the nodes are only set, but clipped to get their size.
    % The final location is not yet known.
    \clip (M);
    \foreach \t [count=\i] in {A, Hello\\World, 3, foobar, $\cdot$} {
      \global\expandafter\let\csname p\i-text\endcsname\t
      \node[main node] (p\i) at (M) {\t};
      %
      \global\let\MainNum\i % the last assignment is number of nodes
      % Calculate the angle between the equal sides of the triangle
      % with side length \MainRadius, \MainRadius and radius of circle node
      % Result is stored in \p1-angle, \p2-angle, ...
      \pgfextracty{\dimen0 }{\pgfpointanchor{p\i}{north}}
      \pgfextracty{\dimen2 }{\pgfpointanchor{p\i}{center}}
      \dimen0=\dimexpr\dimen2 - \dimen0\relax
      \ifdim\dimen0<0pt \dimen0 = -\dimen0 \fi
      \pgfmathparse{2*asin(\the\dimen0/\MainRadius/2)}
      \global\expandafter\let\csname p\i-angle\endcsname\pgfmathresult
      \pgfmathparse{\MainAngleSum + 2*\csname p\i-angle\endcsname}
      \global\let\MainAngleSum\pgfmathresult
    }
  \end{scope}
  \pgfmathsetmacro\MainAngleStep{(360 - \MainAngleSum)/\MainNum}

  % Draw the nodes and arrow arcs
  \global\let\CurrentAngle\MainStartAngle
  \foreach \i in {1, ..., \MainNum} {
    \pgfmathsetmacro\AngleA{\CurrentAngle + \csname p\i-angle\endcsname}
    \pgfmathsetmacro\AngleB{\AngleA + \MainAngleStep}
    \draw
      (M) +(\CurrentAngle:\MainRadius)
      node[main node] {\csname p\i-text\endcsname}
      +(\AngleA:\MainRadius)
      arc[
        start angle=\AngleA,
        end angle=\AngleB,  
        radius=\MainRadius, 
      ]
      ;
    \ifnum\i<\MainNum
      \pgfmathparse{ 
        \AngleB
        + \csname p\the\numexpr\i+1\relax-angle\endcsname
      }
      \global\let\CurrentAngle\pgfmathresult
    \fi
  }
\end{tikzpicture}
\end{document}

Result equidistant