Here's a TikZ solution:
It defines a new command \myTree{}
that takes a comma-separated list of data like <column One / column Two / column Three / column Four>
.
So to get your example, one would use
\myTree{a///, b///, c///, d///, e///, f///}
This works for a variable number of elements in the list:
\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}
The \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}
}
To answer your questions:
- Node coordinates: The easiest way to find the node coordinates is to write some of them down while trying to find a pattern for both the x-coordinate and the y-coordinate. The first 12 nodes have the following coordinates:. So for the x-coordinates that is the sequence:
0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4, 4, ...
. The y-coordinates become: 0, 1, -1, 2, 0, -2, 3, 1, -1, -3, 4, 2, ...
. Now all we need to do is find a formula to generate those sequences. Here the On-Line Encyclopedia of Integer Sequences comes to the rescue (see the sequence references in the code comments). And to decide which node to connect to which node, we can use the exact same method (see second for loop).
- You said "I will eventually be filling each node with columns from each row." To achieve that, one needs to change
{\colOne}
in the line \node at (\x,\y) (\i) {\colOne};
For example changing it to {$\colOne \times \colTwo^\colThree = \colFour$}
will get you:
As one can see, this can get quite crowded. That's why, with the help of xparse
, I added two optional arguments: an x-scale and a y-scale.
So using
\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}
will get you a way better result:
All code combined, the entire document now looks like:
\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}
I changed your input format from a filecontents*
.dat file to an argument list because I think it's more convenient. If you want to keep using your filecontents*
.dat input format though, you can achieve this with the datatool
package and some minor adjustments:
\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}
tree
. So probably there are other solutions. In any case, what happens with non first columns in your data file?