Generate Tikz tree from filecontents

Is there an easy way to create tree nodes from data in a file? I need the tree to have nodes in the format 1,2,3,4 rather than 1,2,4,8 etc. I can't create the nodes in a loop as there would be two child nodes for each node.

I'm picking up the data in each cell and declaring a variable for each entry. Is there an easier way to create the following tree? Each row in the file is a node, and I will eventually be filling each node with columns from each row.

\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}

\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}


At each node, if I could even extract the node coordinate and locate a row in the file with the node reference, that would be a great help in reducing the amount of code.

• I've added the figure I get from your code. If it's not what you want, please delete it and explain it better. I've read somewhere in TeX.SX that this result is not formally a tree. So probably there are other solutions. In any case, what happens with non first columns in your data file? – Ignasi May 27 '15 at 10:44
• Did you think about grahpViz? – Peter Ebelsberger May 30 '15 at 19:59

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}
}


• 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 }{
\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}


• I think you are now an officially recognized TeX.SX addict with this ;) You have been warned. Take it easy otherwise you start writing packages. – percusse Jun 2 '15 at 0:29