3

I have a newbie question. I would like to use TikZ to draw a graph with vertices 0,..,m-1 in a circle, and edges n → n+1 mod m, n → a⋅n mod m, where m=19, a=5, say.

The following attempt almost works - however, the arrows land at the wrong place (always at the rightmost point of the circle around a node):

\begin{tikzpicture}
\def \R {60}
\def \r {9}
\def \radius {\R mm}
\tikzmath{
  \m = 19; \a = 5;
  \margin = 2*atan(\r/(4*\R));
  \mm = \m - 1;
}
\foreach \n in {0,...,\mm}
{
  \node[draw, circle,minimum size=\r mm] (v_\n) at ({90-360/\m * \n}:\radius) {$\n$};
  \draw[->, >=latex, ] ({90-(360/\m * \n+\margin)}:\radius) 
    arc ({90-(360/\m * \n+\margin)}:{90-(360/\m * (\n+1)-\margin)}:\radius);
}

\begin{scope}[->,>=latex,shorten >=1pt,color=red]
\foreach \n in {1,...,\mm}
{
  \tikzmath{\ntimes = Mod(\n*\a,\m);}      
  \draw (v_\n) edge (v_\ntimes);         
}
\path (v_0) edge [loop above] (v_0);
\end{scope}
\end{tikzpicture}

enter image description here

(I know I should also make short edges bend.)

The following code does not compile at all:

  \begin{tikzpicture}
    \def \R {60}
    \def \r {9}
    \def \radius {\R mm}
    \tikzmath{
      \m = 19; \a = 5;
      \margin = 2*atan(\r/(4*\R));
      \mm = \m - 1;
    }
    \graph[clockwise, radius=6cm] {subgraph C_n [n=\m, name=A]};
    \foreach \n in {1,...,\mm} {
        \tikzmath{\ntimes = Mod(\n*\a,\m); \np = Mod(\n+1,\m);}      
        \draw (A \n) -- (A \ntimes);
        \draw (A \n) -- (A \np);
      }
  \end{tikzpicture}

I get the message: "! Package pgf Error: No shape named A 0 is known."

What is the matter in each case?

6
  • 1
    Please, extend your codes fragment to complete document. Also make it compilable: they have undefined commands like tikzmath ...
    – Zarko
    Commented Mar 22, 2020 at 13:42
  • 2
    I guess it's the old problem that \n is a decimal number, so you get e.g. 1.0, not 1. As a result you end up drawing lines to the 0 anchor of the nodes, i.e. the east anchor. Edit: also \ntimes is a decimal, try int(Mod(...)) Commented Mar 22, 2020 at 13:50
  • It would seem \n is not a decimal number, but \ntimes is. Commented Mar 22, 2020 at 14:19
  • All right, that seems to work. Out of curiosity, why does the second version (using the graphs package) not compile? Commented Mar 22, 2020 at 14:25
  • 1
    The nodes are named A 1 through A 19, when \n = 18, \np becomes Mod(18+1,19) = 0, so you're trying to draw a line to a non-existent node (A 0). Commented Mar 22, 2020 at 14:52

2 Answers 2

4

As Torbjørn T. also noticed in the comments (before me it seems...), the problem is that Mod returns numbers like 1.0 so you are drawing nodes to the point at angle zero. I'd also drop the scope environment and, instead, use

[evaluate=\n as \na using {int(Mod(\n*\a,\m))}]]

(and \tikzset) to produce:

enter image description here

Here is the code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta,math,positioning}

\def \R {60}
\def \r {9}
\def \radius {\R mm}
\tikzset{
myedge/.style={->, >=latex, shorten >=1pt, color=red}
}

\newcommand\macircle[2]{% m=#1, a=#2
  \begin{tikzpicture}
    \tikzmath{
      \margin = 2*atan(\r/(4*\R));
      \mm = #1 - 1;
    }
    \foreach \n in {0,...,\mm}
    {
      \node[draw=blue, circle,minimum size=\r mm] (v\n) at ({90-360/#1 * \n}:\radius) {$\n$};
      \draw[->, >=latex, ] ({90-(360/#1 * \n+\margin)}:\radius)
        arc ({90-(360/#1 * \n+\margin)}:{90-(360/#1 * (\n+1)-\margin)}:\radius);
    }

    \foreach \n [evaluate=\n as \na using {int(Mod(\n*#2,#1))}] in {1,...,\mm}
    {
        \draw[myedge] (v\n) -- (v\na);
    }
    \path[myedge] (v0) edge [loop above] (v0);
  \end{tikzpicture}
}

\begin{document}

\macircle{19}{5}
\macircle{17}{6}

\end{document}

I have created your general macro and tweaked things a little.

2
  • Thanks! But what is the advantage of using evaluate rather than tikzmath? Commented Mar 22, 2020 at 14:24
  • @HAHelfgott None that I know of, except that it sometimes means that yo do not need to load the math library. Rather it is a question of aesthetics. Arguably \tizmath is more explicit but I prefer to use evaluate. I guess what I wrote above is misleading as it is the use of \tikzset makes the scope unnecessary not the use of evaluate.
    – user30471
    Commented Mar 22, 2020 at 14:28
1

A small variation of @Andrew answer:

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{arrows.meta}

\begin{document}
    \begin{tikzpicture}[
every edge/.style = {draw=red,-{Straight Barb[angle=60:3pt 3]}, semithick},
every loop/.style = {draw=red,-{Straight Barb[angle=60:3pt 3]}, semithick}
                        ] 

\foreach \i in {0,...,18}
{
  \node (v\i) [circle, draw, minimum size=9mm] at ({90-\i*360/19}:6) {\i};
  \pgfmathsetmacro{\margin}{atan(9/120)}
  \path[every edge]
    ({90+\i*360/19+\margin}:6) arc ({90+\i*360/19+\margin}:{90+(\i+1)*360/19-\margin}:6);
}
\foreach \n in {1,...,18}
{
\pgfmathsetmacro{\nn}{int(Mod(\n*5,19))}
\pgfmathsetmacro{\j}{int(abs(\nn-\n))}
    \ifnum\j<3
        \pgfmathsign{\nn-\n}
        \ifnum\pgfmathresult>0
            \path (v\n) edge[bend right] (v\nn);
        \else
            \path (v\n) edge[bend  left] (v\nn);
        \fi
    \else
        \path (v\n)  edge[blue] (v\nn);
    \fi
}
\path (v0)  edge [loop above] ();
    \end{tikzpicture}
\end{document}

enter image description here

You must log in to answer this question.

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