我是 Tikz 新手,如果这很琐碎,请见谅。我想在 Tikz 中绘制一个凯莱树,看起来就像我在 Google 上找到的图像一样。
问题是我希望交替层是交替的节点形状——圆形和方形节点。其次,我希望圆形节点的度为 3,方形节点的度为 5。有没有办法生成这个,而不必手动将每个节点放置在我想要的位置?
答案1
第二个命题(使用 marsupilam 建议的两个嵌套循环)
(注意:我之前的提议没有使用正确的度数定义。感谢 cfr 和 marsupilam 注意到了这一点。)
这里有一个pdflatex
解决方案。第一个节点(中心)是c-0-1
。第一级节点是c-1-1
,c-1-2
和c-1-3
...第四级节点是c-4-1
,,c-4-2
...和c-4-96
。
\documentclass[tikz]{standalone}
\tikzset{
common/.style={draw,name=#1,node contents={},inner sep=0,minimum size=3},
disc/.style={circle,common=#1},
square/.style={rectangle,common={#1}},
}
\begin{document}
\begin{tikzpicture}
\draw (0,0) node[disc=c-0-1];
\xdef\radius{0cm}
\xdef\level{0}
\xdef\nbnodes{1}
\xdef\degree{(3+1)} % special degree just for the root node
\foreach \ndegree/\form in {5/square,3/disc,5/square,3/disc}{
\pgfmathsetmacro\nlevel{int(\level+1)}
\pgfmathsetmacro\nnbnodes{int(\nbnodes*(\degree-1))}
\pgfmathsetmacro\nradius{\radius+1cm}
\draw[red] (c-0-1) circle(\nradius pt);
\foreach \div in {1,...,\nnbnodes} {
\pgfmathtruncatemacro\src{((\div+\degree-2)/(\degree-1))}
\path (c-0-1) ++({\div*(360/\nnbnodes)-180/\nnbnodes}:\nradius pt) node[\form=c-\nlevel-\div];
\draw (c-\level-\src) -- (c-\nlevel-\div);
}
\xdef\radius{\nradius}
\xdef\level{\nlevel}
\xdef\nbnodes{\nnbnodes}
\xdef\degree{\ndegree}
}
\end{tikzpicture}
\end{document}
答案2
我听从了 JPi 和 cfr 的建议,选择了 lua。
(编辑:我认为这种风格给人一种盛开的樱花的感觉。)
输出
这tikz
使用以下方式编译lualatex
\RequirePackage{luatex85}
\documentclass[12pt,tikz]{standalone}
\usepackage{luacode}
\begin{luacode*}
print=tex.print
makeGrow=require("makeGrow.lua")
\end{luacode*}
\begin{document}
\tikzset
{
odd/.style = {draw=blue!50!pink,circle,ultra thick},
even/.style = {draw=red,line width=3pt,minimum size=4mm},
}
\begin{tikzpicture}[scale=20]
\directlua{makeGrow.make(4)}
\end{tikzpicture}
\end{document}
这lua
-- makeGrow.lua
-- mode = {totalAngle = totalAngle, number = numberOfChildren, radius = lengthOrArm}
local function makeChildren(parent,mode,f)
local f = f or function() return end
parent.children = {}
for k=1,mode.number do
parent.children[k] = {
generation = parent.generation + 1,
angle = parent.angle + (k-.5*(mode.number+1)) * mode.totalAngle / mode.number,
parent = parent,
label = parent.label .. tostring(k),
}
f(parent.children[k]) -- we smuggled f in there to recurse.
end
end
local function tikzNode(node)
return {
name = "(myNode-" .. node.label .. ")",
style = "[" .. ({"even","odd"})[node.generation%2+1] .. "]",
}
end
local function draw(node,mode)
if node.parent then
print([[\path]] .. tikzNode(node.parent).name .. " -- ++(" .. node.angle .. ":" .. mode.radius .. ") node" .. tikzNode(node).style .. tikzNode(node).name .. "{} ;")
print([[\draw]] .. tikzNode(node.parent).name .. " -- " .. tikzNode(node).name .. ";")
else
print([=[\node[odd]]=] .. tikzNode(node).name .. "at (0,0) {};")
end
end
local function drawMakeChild(n,modes)
local function recurse(node)
draw(node,modes[node.generation-1])
if node.generation<=n then
makeChildren(node,modes[node.generation],recurse)
end
end
return recurse
end
local function computeMode(generation,hash)
local number = ({5,3})[generation%2+1] -- alternating number of children
local radius = hash.radRatio^generation
local totalAngle = 360 * hash.angRatio^(generation-1)
return {totalAngle = totalAngle , number = number, radius = radius}
end
local function make(n)
local origin = {
generation = 1,
angle = 0,
label = ""
}
local modes = {}
for k=1,n do modes[k] = computeMode(k,{angRatio=.98,radRatio=.35}) end
drawMakeChild(n,modes)(origin)
end
return {make=make}
编辑:使用 Paul 的风格
输出
或\def\N{4}
这tikz
\RequirePackage{luatex85}
\documentclass[12pt,tikz]{standalone}
\usepackage{luacode}
\begin{luacode*}
print=tex.print
makeGrow=require("paulStyle.lua")
\end{luacode*}
\begin{document}
\tikzset
{
commons/.style={fill=white},
odd/.style = {draw=red,circle,ultra thick,commons},
even/.style = {draw=blue,ultra thick,minimum size=3mm,commons},
}
\def\N{3}
\begin{tikzpicture}[scale=4]
\foreach \k in {1,...,\N} \draw[help lines,purple] (0,0) circle (\k);
\directlua{makeGrow.make(\N)}
\end{tikzpicture}
\end{document}
这lua
-- paulStyle.lua
local function makeChildren(parent,multiplicity,f)
parent.children = {}
for k=1,multiplicity do
parent.children[k] = {
generation = parent.generation + 1,
cumProd = parent.cumProd * multiplicity,
angle = parent.angle + ((k-.5)/multiplicity-.5 ) * 360 / parent.cumProd,
parent = parent,
label = parent.label .. tostring(k),
}
f(parent.children[k]) -- we smuggled f in there to recurse.
end
end
local function tikzNode(node)
return {
name = "(myNode-" .. node.label .. ")",
style = "[" .. ({"odd","even"})[node.generation%2+1] .. "]",
}
end
local function draw(node)
if node.parent then
print([[\node]].. tikzNode(node).style .. tikzNode(node).name .. " at " .. "(" .. node.angle .. ":" .. node.generation .. ") {};")
print([[\draw]] .. tikzNode(node.parent).name .. " -- " .. tikzNode(node).name .. ";")
else
print([=[\node]=] .. tikzNode(node).style .. tikzNode(node).name .. "at (0,0) {};")
end
end
local function drawMakeChild(n,multiplicities)
local function recurse(node)
draw(node,multiplicities[node.generation-1])
if node.generation<n then
makeChildren(node,multiplicities[node.generation],recurse)
end
end
return recurse
end
local function make(n)
local origin = {
cumProd = 1,
generation = 0,
angle = 0,
label = ""
}
local multiplicities = {}
for k=1,n do multiplicities[k-1] = ({5,3})[k%2+1] end
drawMakeChild(n,multiplicities)(origin)
end
return {make=make}
答案3
这是我的。尽管我发表了评论,但事实上,这是纯钛钾Z 没有任何内容graphs
。也就是说,你可以用 LaTeX、pdfLaTeX 或其他任何东西来编译它,它应该可以工作。(如果你愿意的话,你可以把它转换成 TeX 版本。)我计划用它graphs
来绘制连接,这不需要 LuaTeX。但不知何故,我从来没有这样做过,因为一旦我放置了节点,这似乎更容易。
更改外循环的最大值以增加层数。我练习时使用了 3 和 4 的值,但这里对“显示”版本使用了 5。复杂之处在于,第一个节点有 3 个子节点,以便具有 3 度,而后面的 3 度节点只需要 2 个,因为它们有一个父节点。这需要对前 3 个层进行特殊处理,以使事物正确排列。之后,后续层只是 TeX 容量和您的耐心的问题。
用于\showtrue
绘制标记版本,以用于调试目的。
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\newif\ifshow\showfalse % set true to debug
\begin{document}
\begin{tikzpicture}
% \i: level \s: shape \a: angle \t: turn \d: degree -1 \j: number \m: rotation \g: group \k: number \c: colour
\def\j{1}\def\dlast{1}\def\tlast{0}
\foreach \i [remember=\i as \ilast] in {0,...,5}
{
\draw [darkgray] (0,0) circle (\i cm);
\pgfmathsetmacro\a{360/\j}
\ifodd\i\def\s{}\def\c{magenta}\def\d{4}\pgfmathsetmacro\t{\tlast-1.5*\a}\else\def\c{blue!50!cyan}\def\s{circle}\def\d{2}\pgfmathsetmacro\t{\tlast-2.5*\a}\fi
\ifnum\i=1\pgfmathsetmacro\t{-\a}\fi
\ifnum\i=0\def\d{3}\def\t{0}\fi
\foreach \k [evaluate=\k as \m using {(\k*\a)+\t}, evaluate=\k as \g using {int((floor((\k-1)/\dlast)))}, count=\n from 0 ] in {1,...,\j}
{
\ifshow\def\tempa{n-\i-\g-\n:\k}\else\let\tempa\relax\fi
\node (n-\i-\n) [draw, fill, \c, \s, minimum size=2.5pt, inner sep=0pt, label={[font=\tiny]{\tempa}} ] at (\m:\i cm) {};
\ifnum\i>0 \draw [darkgray] (n-\i-\n) -- (n-\ilast-\g); \fi
}
\pgfmathsetmacro\j { \j*\d }
\global\let\j\j
\global\let\dlast\d
\pgfmathsetmacro\tlast{(\i==1) ? 0 : (\t+\a) }
\global\let\tlast\tlast
}
\end{tikzpicture}
\end{document}
这是一个更加参数化的版本,带有(可选)特殊效果。
circle colour=<colour>
将为圆圈提供统一的颜色;circle colours=<colour>:<colour>
将使圆圈呈现出两种颜色之间的不同色调;square colour=<colour>
将为圆圈提供统一的颜色;square colours=<colour>:<colour>
将使方块呈现出两种颜色之间的不同色调;circle degree=<integer>
设置圆形节点的度数;square degree=<integer>
设置方形节点的度;connection colour<colour>
设置圆圈和背景的颜色;levels=<integer>
设置级别数。
如果你不想要背景,只需删除该行
\scoped[on background layer]{\shade [inner color=lcol!5, outer color=lcol!35] circle (\l cm);}
在这种情况下,您不需要该backgrounds
库,可以删除
\usetikzlibrary{backgrounds}
如果你不需要它做其他任何事情。
\documentclass[border=10pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\newif\ifshow\showfalse % set true to debug
\begin{document}
\begin{tikzpicture}
% \i: level \s: shape \a: angle \t: turn \d: degree -1 \j: number \m: rotation \g: group \k: number ncol: colour
\tikzset{
circle degree/.code={\def\dr{#1}\pgfmathsetmacro\dc{int(#1-1)}\pgfmathsetmacro\tc{((\dc-1)/2)+1}},
square degree/.code={\pgfmathsetmacro\ds{int(#1-1)}\pgfmathsetmacro\ts{((\ds-1)/2)+1}},
levels/.code={\pgfmathsetmacro\l{int(#1-1)}},
connection colour/.code={\colorlet{lcol}{#1}},
circle colours/.code args={#1:#2}{\colorlet{ccol1}{#1}\colorlet{ccol2}{#2}},
square colours/.code args={#1:#2}{\colorlet{scol1}{#1}\colorlet{scol2}{#2}},
circle colour/.style={circle colours=#1:#1},
square colour/.style={square colours=#1:#1},
circle degree=3,
square degree=5,
levels=6,
connection colour=darkgray,
square colours=green:blue,
circle colours=blue:magenta,
}
\def\j{1}\def\dlast{1}\def\tlast{0}
\foreach \i [remember=\i as \ilast] in {0,...,\l}
{
\draw [lcol] (0,0) circle (\i cm);
\pgfmathsetmacro\a{360/\j}
\pgfmathsetmacro\z{6.5-\i*.8}
\ifodd\i\def\s{}\colorlet{ncol1}{scol1}\colorlet{ncol2}{scol2}\let\d\dc\pgfmathsetmacro\t{\tlast-\ts*\a}\else\colorlet{ncol1}{ccol1}\colorlet{ncol2}{ccol2}\def\s{circle}\let\d\ds\pgfmathsetmacro\t{\tlast-\tc*\a}\fi
\ifnum\i=1\pgfmathsetmacro\t{-\a}\fi
\ifnum\i=0\let\d\dr\def\t{0}\fi
\foreach \k [evaluate=\k as \m using {(\k*\a)+\t}, evaluate=\k as \g using {int((floor((\k-1)/\dlast)))}, count=\n from 0, evaluate=\k as \p using { (\k > \j/2) ? ((1-\k/\j)*200) : ((200/\j)*\k)} ] in {1,...,\j}
{
\ifshow\def\tempa{n-\i-\g-\n:\k}\else\let\tempa\relax\fi
\node (n-\i-\n) [draw, fill, ncol1!\p!ncol2, \s, minimum size=\z pt, inner sep=0pt, label={[font=\tiny]{\tempa}} ] at (\m:\i cm) {};
\ifnum\i>0 \draw [ncol1!\p!ncol2] (n-\i-\n) -- (n-\ilast-\g); \fi
}
\pgfmathsetmacro\j { \j*\d }
\global\let\j\j
\global\let\dlast\d
\pgfmathsetmacro\tlast{(\i==1) ? 0 : (\t+\a) }
\global\let\tlast\tlast
}
\scoped[on background layer]{\shade [inner color=lcol!5, outer color=lcol!35] circle (\l cm);}
\end{tikzpicture}
\end{document}