10

Can I draw something like this programmatically with LaTeX?

I drew these with Adobe Illustrator, but it gets pretty time-consuming.
Even with relatively few nodes. What it attempts to demonstrate is the number of "symmetric" cryptographic keys required for secure communication between n parties - for which the formula is n(n-1)/2 (I tried to render that with LaTeX/MathJax, but it won't let me for some reason).

enter image description here

And it's hard to get it perfect. It's always off by a small amount, as you can see here. It might not seem like much but with a lot of nodes, it can add up and skew the output, and cause problems when trying to get everything to fit properly.

enter image description here

I wanted to draw a big one with up up to 100 nodes, so it would be best if I could do it programmatically, rather than having to type up several hundred lines of code manually. Is that kind of thing possible with LaTeX? I heard someone say TeX is a full Turing complete programming language. If that's true, I'm not sure, but it would probably make it pretty useful for generating diagrams with this kind of data, kinda like D3.js.

As you can see, by the time you get to 10 or 11 vertices, it can be pretty unruly:

enter image description here

voices
  • 2,039
  • After all, 100 vertices is a lot. How are you going to arrange vertices? – Symbol 1 May 31 '19 at 17:23
  • @Symbol1 Same as I have been, probably. Around. A circle or a polygon. Doesn't necessarily have to be 100 vertices, I want to be able to specify an arbitrary number, and produce a graph with that many interconnected nodes. In a similar fashion to what I've drawn. I experimented with your GitHub code and got it to do some cool things, but I was just hacking around, manipulating values, not really understanding a lot of it. – voices May 31 '19 at 18:15
  • Consider accepting the provided answer since it seems to answer your question. – Dr. Manuel Kuehner May 31 '19 at 18:28
  • @tjt263 Would you mind sharing in which context you're going to use it? – hola May 31 '19 at 18:29
  • The same is true for some of your other questions. – Dr. Manuel Kuehner May 31 '19 at 18:30

2 Answers2

12

Yes, you can.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{arrows.meta}
\newcounter{pft}
\begin{document}
\begin{tikzpicture}[font=\sffamily,pics/cgram/.style={code={
\foreach \XX [count=\YY starting from 0] in {1,...,#1}
{\pgfmathsetmacro{\mycolor}{{\LstCols}[\YY]}
\node[circle,draw,minimum size=2.5em,fill=\mycolor] (c-#1-\XX) at 
({{\LstAngles}[#1-2]-\YY*360/#1}:1.5) {\setcounter{pft}{\XX}\Alph{pft}};}
\foreach \XX [evaluate=\XX as \Ymax using {int(\XX-1)}] in {2,...,#1}
{\foreach \YY  in {1,...,\Ymax}
{\pgfmathsetmacro{\mycolorA}{{\LstCols}[\XX-1]}
\pgfmathsetmacro{\mycolorB}{{\LstCols}[\YY-1]}
\path (c-#1-\XX) -- (c-#1-\YY) coordinate[pos=0.1] (aux0) coordinate[pos=0.9] (aux1);
\fill[black] (aux0) to[bend left=2] (aux1) to[bend left=2] (aux0);
\draw[{Stealth[fill=\mycolorB,length=7pt,inset=2pt]}-{Stealth[fill=\mycolorA,length=7pt,inset=2pt]}] (c-#1-\XX) -- (c-#1-\YY);
}}}}]
\def\LstCols{"red","orange","yellow","green!70!black","blue!70!white","purple!80!white"}
\def\LstAngles{180,150,135,128,150}
\path (-5,0) pic {cgram=2} (0,0.5) pic {cgram=3} (5,0) pic {cgram=4}
 (-3,-4) pic {cgram=5}  (3,-4) pic {cgram=6};
\end{tikzpicture}
\end{document}

enter image description here

Zoom in:

enter image description here

And yes, for large numbers N of nodes it becomes busy, simply since the number of connections goes like N (N-1)/2.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{arrows.meta}
\definecolor{colorA}{RGB}{202, 38, 49} 
\definecolor{colorB}{RGB}{222, 146, 60} 
\definecolor{colorC}{RGB}{240, 215, 68} 
\definecolor{colorD}{RGB}{126, 183, 86} 
\definecolor{colorE}{RGB}{98, 173, 233} 
\definecolor{colorF}{RGB}{158, 76, 150}  
\newcounter{pft}
\tikzset{pics/cgram/.style={code={
\foreach \XX [count=\YY starting from 0] in {1,...,#1}
{\pgfmathtruncatemacro{\iA}{mod(\XX-1,6)+1}
\pgfmathsetmacro{\mycolor}{{\LstCols}[\iA-1]}
\node[circle,draw,minimum size=2.5em,fill=\mycolor] (c-#1-\XX) at 
({-\YY*360/#1}:\pgfkeysvalueof{/tikz/cgram radius}) {\setcounter{pft}{\iA}\Alph{pft}};}
\foreach \XX [evaluate=\XX as \Ymax using {int(\XX-1)}] in {2,...,#1}
{\foreach \YY  in {1,...,\Ymax}
 {\pgfmathtruncatemacro{\iA}{mod(\XX-1,6)+1}
  \pgfmathtruncatemacro{\iB}{mod(\YY-1,6)+1}
  \pgfmathsetmacro{\mycolorA}{{\LstCols}[\iA-1]}
  \pgfmathsetmacro{\mycolorB}{{\LstCols}[\iB-1]}
 \draw[{Stealth[fill=\mycolorB,length=7pt,inset=2pt]}-{Stealth[fill=\mycolorA,length=7pt,inset=2pt]}] (c-#1-\XX) -- (c-#1-\YY);
}}
}},cgram radius/.initial=1.5}
\begin{document}
\foreach \Nmax in {2,4,...,40}
{\begin{tikzpicture}[font=\sffamily]
\draw (-11,-11) rectangle (11,11);
\def\LstCols{"colorA","colorB","colorC","colorD","colorE","colorF"}
\pgfmathsetmacro{\myradius}{sqrt(2.5*\Nmax)}
\path  pic[cgram radius=\myradius] {cgram=\Nmax};
\end{tikzpicture}}
\end{document}

enter image description here

  • I doubt that it is necessary to use anchors. The Inscribed angle is half the arc. – Symbol 1 May 31 '19 at 05:43
  • @Symbol1 Sorry, what do you mean? Where am I using an anchor? –  May 31 '19 at 05:45
  • This (c-#1-\XX), is what I understand as anchor. It is essentially (c-#1.\XX), right? – Symbol 1 May 31 '19 at 05:47
  • @Symbol1 Not at all. This is just the name of the node, these are hyphens, not minuses. Note that shapes.geometric was not used here, and I am removing it now. (Anchors come with ., not -.) –  May 31 '19 at 05:48
  • PS just in case anybody cares about the colors, I had a bit of a play with it, and I used "cyan" and "violet!80!magenta!70" (or something like that), instead of "blue" and "purple". The "blue" is pretty much indigo, so you could probably do a full spectrum (i.e. ROYGBIV) with "red", "orange", "yellow", "green", "cyan", "blue", "violet". Also I came across a big swatch pad at over at http://latexcolor.com/ (most will require \usepackage[usenames,dvipsnames]{xcolor} in the preamble). – voices May 31 '19 at 07:29
  • 1
    @marmot What I meant was this: in my construction, I can avoid \LstAngles{180,150,135,128,150} because TikZ will choose the right angle automatically. – Symbol 1 May 31 '19 at 07:34
  • 2
    +1: Surprisingly little code needed for that. – Dr. Manuel Kuehner May 31 '19 at 10:29
  • @Symbol1 What you propose is certainly neat but is this really what you meant by anchors? Also in your construction the orientation is different from the OP's, yours is counterclockwise while the OP's and mine are clockwise and in your code the shape with six vertices is rotated. The angles were only to reproduce the OP's screen shot. –  May 31 '19 at 13:47
  • 1
    @marmot Can you please explain your code a bit? – voices May 31 '19 at 15:07
  • @tjt263 All I am doing is to declare a pic that has one argument, the number of nodes. These nodes are placed clockwise (because they are clockwise in your screen shot) equidistantly around a (virtual) circle, and filled with colors that is stored in \LstCols, and with letters A, B, ..... Then all nodes are connected with arrows, whereby the arrow head at a given node has the color of the node the arrow comes from. The list of angles is introduced to match the orientation of your screen shot, they determine the angle of node A.. –  May 31 '19 at 15:14
  • @tjt263 In order to match your colors, use \definecolor{colorA}{RGB}{202, 38, 49} \definecolor{colorB}{RGB}{222, 146, 60} \definecolor{colorC}{RGB}{240, 215, 68} \definecolor{colorD}{RGB}{126, 183, 86} \definecolor{colorE}{RGB}{98, 173, 233} \definecolor{colorF}{RGB}{158, 76, 150} and \def\LstCols{"colorA","colorB","colorC","colorD","colorE","colorF"}. –  May 31 '19 at 15:29
  • @tjt263 All you need to do then is to add some entries to the list of colors and to the list of angles, and then you can do \path pic {cgram=N};, where N is an integer. –  May 31 '19 at 15:43
  • so, if i want 100 nodes, i need to enter all the angles? – voices May 31 '19 at 15:45
  • @tjt263 Not if there is a prescription what the diagram should look like. For N=100 you need also to adjust the radius. –  May 31 '19 at 15:48
  • Maybe you could point out which pieces of code perform which function. – voices May 31 '19 at 16:08
  • @marmot Never mind; I finally understand your construction. – Symbol 1 May 31 '19 at 17:06
  • Well my friend, this is a piece of art! – hola May 31 '19 at 18:28
  • Actually, I shouldn't say the TikZ manual sucks. It too has a lot of good things about it. The thing is, it'd only require a tiny effort to improve it a hundredfold; to transition from barely useful to excellent. As it stands, it's barely useable despite all the good things about it. Mainly because it assumes too much prior knowledge. It's written by those with the most experience, in a style that's most applicable to them. So that's good for the 1% of us who are already experts. Not so useful for the 99% of us that actually want/need guidance. Because that's what it should do; guide us. – voices Jul 08 '19 at 15:59
  • 1
    @tjt263 You might be interested in https://github.com/pgf-tikz/pgf/issues/640#issuecomment-504888430. I am working on this, but did not accomplish much so far since I have a problem that parallels yours: I do not understand how to deal with github. So I think I know how you feel. On the other hand, I feel that the situations are different in that I usually add explanations if I get asked on something specific. However, as of now I have not yet received answers to my github questions that allow me to get going. This is mostly my fault, but also the fact that I did not find a manual on this. –  Jul 08 '19 at 17:30
  • 1
    I have cleaned up some comments here: they don't really help to refine the answer (which ultimately is the aim of comment threads). – Joseph Wright Aug 06 '19 at 09:00
4

So this is my construction for future references.

\documentclass[border=9,tikz,rgb]{standalone}

\usetikzlibrary{arrows.meta,decorations.pathreplacing}
\begin{document}

\tikzset{
    /pgf/arrow keys/colorsize/.style={fill=#1,length=10pt}
}
\def\N{70}
\tikzdeclarecoordinatesystem{sunflower}{ % #1 is the index of vertex
    \pgfmathsetmacro\sunindex{#1-.5}
    \pgfmathsetmacro\sunangle{mod(\sunindex*16.18034,10)*36}
    \pgfmathsetmacro\sunradius{sqrt(\sunindex)*50}
    \pgfpointpolar{\sunangle}{\sunradius}
}
\globalcolorstrue
\def\definesuncolor#1{
    \pgfmathtruncatemacro\sunindex{#1-.5}
    \pgfmathsetmacro\sunhue{mod(\sunindex*16.18034,10)*36}
    \pgfmathsetmacro\sunsaturation{sqrt(\sunindex/\N)}
    \definecolor{sun#1}{Hsb}{\sunhue,\sunsaturation,1}
}
\tikz{
    \foreach\i in{1,...,\N}{
        \definesuncolor{\i}
        \path(sunflower cs:\i)node(vertex\i)
            [circle,draw,minimum size=2cm,line width=6pt]{};
        \fill[sun\i](vertex\i)+(1pt,1pt)circle(1);
    }
    \foreach\i in{2,...,\N}{
        \foreach\j in{1,...,\numexpr\i-1}{
            \path[scale=.666/sqrt(\N)]
                [shift=(vertex\i)](sunflower cs:\j)coordinate(X-\i-\j)
                [shift=(vertex\j)](sunflower cs:\i)coordinate(Y-\i-\j);
            \draw[{Stealth[colorsize=sun\j]}-{Stealth[colorsize=sun\i]}]
                [line width=.1](X-\i-\j)--(Y-\i-\j);
        }
    }
    \foreach\i in{2,...,\N}{
        \foreach\j in{1,...,\numexpr\i-1}{
            \draw[{Stealth[colorsize=sun\j]}-{Stealth[colorsize=sun\i]}]
                [dash pattern=on0off9999](X-\i-\j)--(Y-\i-\j);
        }
    }
}

\end{document}

Some comments to whomever wants to play with this:

  • sunflower is the coordinate system that controls how to place vertices. It is the same algorithm that sunflower uses to place its seeds. See wikipedia
  • The color of each vertex is control by \definesuncolor#1. Currently it is defined such that the sunflower looks like the HSB wheel.
  • There are two nested-for-loops at the end. The former loop draws the edge, the later loop draws the arrow tips.
  • The position of arrow tip is controlled by (X-\i-\j) and (Y-\i-\j). Currently they are the relative positions of the vertices. So the arrows tips on each vertex also looks like the HSB wheel.

Symbol 1
  • 36,855