有没有一种简单的方法可以根据文件中的数据创建树节点?我需要树的节点格式为 1,2,3,4,而不是 1,2,4,8 等。我无法在循环中创建节点,因为每个节点有两个子节点。
我正在提取每个单元格中的数据并为每个条目声明一个变量。有没有更简单的方法来创建以下树?文件中的每一行都是一个节点,我最终将用每行的列填充每个节点。
\documentclass{standalone}
\usepackage{catchfile,tikz}
\usepackage{pgfplotstable}
\usepackage{filecontents}
\begin{filecontents*}{\jobname.dat}
a&1&2&3\\
b&1&2&3\\
c&1&2&3\\
d&1&2&3\\
e&1&2&3\\
f&1&2&3\\
\end{filecontents*}
\begin{document}
\pgfplotstableread[col sep=&,header=false]{\jobname.dat}{\firsttable}
\pgfplotstablegetelem{0}{[index]0}\of{\firsttable} \let\RowZeroColZero\pgfplotsretval
\pgfplotstablegetelem{1}{[index]0}\of{\firsttable} \let\RowOneColZero\pgfplotsretval
\pgfplotstablegetelem{2}{[index]0}\of{\firsttable} \let\RowTwoColZero\pgfplotsretval
\pgfplotstablegetelem{3}{[index]0}\of{\firsttable} \let\RowThreeColZero\pgfplotsretval
\pgfplotstablegetelem{4}{[index]0}\of{\firsttable} \let\RowFourColZero\pgfplotsretval
\pgfplotstablegetelem{5}{[index]0}\of{\firsttable} \let\RowFiveColZero\pgfplotsretval
\begin{tikzpicture} [grow=right, sloped,dot/.style={circle,fill,inner sep=0.5pt}]
\coordinate
node{\RowZeroColZero}
child {
node {\RowTwoColZero}
child {node {\RowFiveColZero}}
child {node[text opacity = 0] {\RowFiveColZero}}
}
child {
node {\RowOneColZero}
child {node {\RowFourColZero}}
child {node {\RowThreeColZero}}
}
;
\end{tikzpicture}
\end{document}
在每个节点上,如果我甚至可以提取节点坐标并使用节点引用在文件中定位一行,那么这将对减少代码量有很大帮助。
答案1
这是 Ti钾Z解决方案:
它定义了一个新命令\myTree{}
,该命令采用逗号分隔的数据列表,如<column One / column Two / column Three / column Four>
。
因此,为了得到你的例子,可以使用
\myTree{a///, b///, c///, d///, e///, f///}
这适用于列表中可变数量的元素:
\begin{enumerate}
\item \ \\\myTree{a/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3, e/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3, e/1/2/3, f/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3, e/1/2/3, f/1/2/3, g/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3, e/1/2/3, f/1/2/3, g/1/2/3, h/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3, e/1/2/3, f/1/2/3, g/1/2/3, h/1/2/3, i/1/2/3}
\item \ \\\myTree{a/1/2/3, b/1/2/3, c/1/2/3, d/1/2/3, e/1/2/3, f/1/2/3, g/1/2/3, h/1/2/3, i/1/2/3, j/1/2/3}
\end{enumerate}
这\myTree
:
\newcounter{total}
\newcommand{\myTree}[1]{
\begin{tikzpicture}
\setcounter{total}{0}
\foreach \colOne/\colTwo/\colThree/\colFour [count=\i] in {#1} {
\stepcounter{total};
\pgfmathtruncatemacro{\x}{-1/2+sqrt(\i*2)}; % Sequence A002024
\pgfmathtruncatemacro{\t}{(-1+sqrt(\i*8-7))/2};
\pgfmathtruncatemacro{\y}{(\t*\t+3*\t+4)/2-2*\i+\t*(\t+1)/2} % Sequence A114327
\node at (\x,\y) (\i) {\colOne};
}
\pgfmathtruncatemacro{\canUp}{\thetotal-floor((sqrt(\thetotal*8+1)-1)/2)+1} % Sequence A083920
\pgfmathtruncatemacro{\canDown}{\thetotal-1-floor((sqrt((\thetotal-1)*8+1)-1)/2)+1} % Sequence A083920
\foreach \colOne/\colTwo/\colThree/\colFour [count=\i] in {#1} {
\pgfmathtruncatemacro{\up}{\i+round(sqrt(2*\i))}; % Sequence A014132
\pgfmathtruncatemacro{\down}{\up+1}; % Sequence A080036
\ifnum \i < \canUp \draw (\i) -- (\up); \fi
\ifnum \i < \canDown \draw (\i) -- (\down);\fi
}
\end{tikzpicture}
}
回答您的问题:
- 节点坐标:找到节点坐标的最简单方法是写下其中一些坐标,同时尝试找到 x 坐标和 y 坐标的模式。前 12 个节点具有以下坐标:。因此,对于 x 坐标,序列为:
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, ...
。y 坐标变为:0, 1, -1, 2, 0, -2, 3, 1, -1, -3, 4, 2, ...
。现在我们需要做的就是找到一个公式来生成这些序列。这里整数序列在线百科全书来帮忙了(参见代码注释中的序列引用)。至于决定哪个节点连接到哪个节点,我们可以使用完全相同的方法(参见第二个 for 循环)。 - 您说“我最终将用每行的列填充每个节点。” 为了实现这一点,需要更改
{\colOne}
行\node at (\x,\y) (\i) {\colOne};
例如将其更改为{$\colOne \times \colTwo^\colThree = \colFour$}
将获得:
可以看出,这会变得相当拥挤。这就是为什么在 的帮助下xparse
,我添加了两个可选参数:x 比例和 y 比例。
因此使用
\myTree[2.2][1.5]{ a / 1 / 2 / 3,
b / 1 / 2 / 3,
c / 1 / 2 / 3,
d / 1 / 2 / 3,
e / 1 / 2 / 3,
f / 1 / 2 / 3}
将会得到更好的结果:
所有代码合并后,整个文档现在如下所示:
\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\newcounter{total}
\DeclareDocumentCommand{\myTree}{ O{1.0} O{1.0} m }{
\begin{tikzpicture}
\setcounter{total}{0}
\pgfmathsetmacro{\xscale}{#1}
\pgfmathsetmacro{\yscale}{#2}
\foreach \colOne/\colTwo/\colThree/\colFour [count=\i] in {#3} {
\stepcounter{total};
\pgfmathsetmacro{\x}{\xscale*floor(-1/2+sqrt(\i*2))}; % Sequence A002024
\pgfmathtruncatemacro{\t}{(-1+sqrt(\i*8-7))/2};
\pgfmathsetmacro{\y}{\yscale*((\t*\t+3*\t+4)/2-2*\i+\t*(\t+1)/2)} % Sequence A114327
\node at (\x,\y) (\i) {$\colOne \times \colTwo^\colThree = \colFour$};
}
\pgfmathtruncatemacro{\canUp}{\thetotal-floor((sqrt(\thetotal*8+1)-1)/2)+1} % Sequence A083920
\pgfmathtruncatemacro{\canDown}{\thetotal-1-floor((sqrt((\thetotal-1)*8+1)-1)/2)+1} % Sequence A083920
\foreach \colOne/\colTwo/\colThree/\colFour [count=\i] in {#3} {
\pgfmathtruncatemacro{\up}{\i+round(sqrt(2*\i))}; % Sequence A014132
\pgfmathtruncatemacro{\down}{\up+1}; % Sequence A080036
\ifnum \i < \canUp \draw (\i) -- (\up); \fi
\ifnum \i < \canDown \draw (\i) -- (\down);\fi
}
\end{tikzpicture}
}
\begin{document}
\myTree[2.2][1.5]{ a / 1 / 2 / 3,
b / 1 / 2 / 3,
c / 1 / 2 / 3,
d / 1 / 2 / 3,
e / 1 / 2 / 3,
f / 1 / 2 / 3}
\end{document}
我将您的输入格式从filecontents*
.dat 文件更改为参数列表,因为我认为这样更方便。但是,如果您想继续使用filecontents*
.dat 输入格式,您可以使用该datatool
包并进行一些细微调整来实现这一点:
\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usepackage{filecontents, datatool}
\begin{filecontents*}{jobname1.dat}
a&1&2&3\\
b&1&2&3\\
c&1&2&3\\
d&1&2&3\\
e&1&2&3\\
f&1&2&3\\
\end{filecontents*}
\begin{filecontents*}{jobname2.dat}
a&1&2&3\\
b&1&2&3\\
c&1&2&3\\
d&1&2&3\\
\end{filecontents*}
\DTLsetseparator{&}
\newcounter{total}
\newcounter{counter}
\DeclareDocumentCommand{\myTree}{ O{1.0} O{1.0} m }{
\DTLloaddb[noheader]{#3}{#3}
\begin{tikzpicture}
\setcounter{total}{0}
\pgfmathsetmacro{\xscale}{#1}
\pgfmathsetmacro{\yscale}{#2}
\DTLforeach*{#3}{\colOne=Column1, \colTwo=Column2, \colThree=Column3, \colFour=Column4}{
\stepcounter{total};
\pgfmathsetmacro{\x}{\xscale*floor(-1/2+sqrt(\thetotal*2))}; % Sequence A002024
\pgfmathtruncatemacro{\t}{(-1+sqrt(\thetotal*8-7))/2};
\pgfmathsetmacro{\y}{\yscale*((\t*\t+3*\t+4)/2-2*\thetotal+\t*(\t+1)/2)} % Sequence A114327
\node at (\x,\y) (\thetotal) {$\colOne \times \colTwo^\colThree = \colFour$};
}
\pgfmathtruncatemacro{\canUp}{\thetotal-floor((sqrt(\thetotal*8+1)-1)/2)+1} % Sequence A083920
\pgfmathtruncatemacro{\canDown}{\thetotal-1-floor((sqrt((\thetotal-1)*8+1)-1)/2)+1} % Sequence A083920
\setcounter{counter}{0}
\DTLforeach*{#3}{}{
\stepcounter{counter}
\pgfmathtruncatemacro{\up}{\thecounter+round(sqrt(2*\thecounter))}; % Sequence A014132
\pgfmathtruncatemacro{\down}{\up+1}; % Sequence A080036
\ifnum \thecounter < \canUp \draw (\thecounter) -- (\up); \fi
\ifnum \thecounter < \canDown \draw (\thecounter) -- (\down);\fi
}
\end{tikzpicture}
}
\begin{document}
\myTree{jobname1.dat}
\myTree[2.2][1.5]{jobname2.dat}
\end{document}