我可以使用 LaTeX 以编程方式绘制类似的东西吗?
我使用 Adobe Illustrator 绘制了这些图,但绘制起来非常耗时。
即使节点相对较少。它试图演示的是安全通信所需的“对称”加密密钥的数量n各方 - 其公式为n(n-1)/2(我尝试使用 LaTeX/MathJax 来渲染它,但由于某种原因它不允许我这样做)。
而且很难做到完美。正如您在此处看到的,它总是会有少量偏差。这看起来可能不多,但如果节点很多,它就会累加并扭曲输出,并在尝试使所有内容正确匹配时导致问题。
我想画一个多达 100 个节点的大图,所以最好能用编程的方式完成,而不是手动输入几百行代码。LaTeX 能做到吗?我听说有人说 TeX 是一种完整的图灵完备编程语言。如果这是真的,我不确定,但它可能对用这种数据生成图表非常有用,有点像D3.js。
正如你所见,当你到达 10 或 11 个顶点时,它会变得非常难以控制:
答案1
是的你可以。
\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}
放大:
是的,对于大量N
节点来说,它会变得繁忙,因为连接数量就像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}
答案2
这是我为将来的参考而构建的。
\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}
对任何想玩这个游戏的人的一些评论:
sunflower
是控制如何放置顶点的坐标系。这与向日葵放置种子的算法相同。请参阅维基百科- 每个顶点的颜色由 控制
\definesuncolor#1
。目前它被定义为使向日葵看起来像 HSB 轮。 - 最后有两个嵌套的 for 循环。前一个循环绘制边缘,后一个循环绘制箭头尖端。
- 箭头的位置由
(X-\i-\j)
和控制(Y-\i-\j)
,目前它们是顶点的相对位置,所以每个顶点上的箭头看起来也像 HSB 轮。