从文件内容生成 Tikz 树

从文件内容生成 Tikz 树

有没有一种简单的方法可以根据文件中的数据创建树节点?我需要树的节点格式为 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

这是 TiZ解决方案:

它定义了一个新命令\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}

在此处输入图片描述

相关内容