2

I'm trying to draw a large family/directory tree using tikz-tree. I've found this question in Stackexchange, which almost works, but not quite. Using the code provided in the answer I get overlapping text when my tree is sufficiently large. If I don't use the tighter intendation, nodes do not overlap, but I don't get wanted intendation (and the tree becomes too wide).

Example for clarity

\documentclass[11pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\makeatletter
\newcount\dirtree@lvl
\newcount\dirtree@plvl
\newcount\dirtree@clvl
\def\dirtree@growth{%
  \ifnum\tikznumberofcurrentchild=1\relax
  \global\advance\dirtree@plvl by 1
  \expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}
  \fi
  \global\advance\dirtree@lvl by 1\relax
  \dirtree@clvl=\dirtree@lvl
  \advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname
  \pgf@xa=1cm\relax
  \pgf@ya=-0.5cm\relax
  \pgf@ya=\dirtree@clvl\pgf@ya
  \pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
  \ifnum\tikznumberofcurrentchild=\tikznumberofchildren
  \global\advance\dirtree@plvl by -1
  \fi
}

\tikzset{
  dirtree/.style={
    growth function=\dirtree@growth,
    growth parent anchor=south west,
    parent anchor=south west,
    every child node/.style={anchor=west},
    edge from parent path={([xshift=2ex] \tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}
  }
}
\tikzset{
  dirtreemid/.style={
    growth function=\dirtree@growth,
    every node/.style={anchor=north},
    every child node/.style={anchor=west},
    edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)}
  }
}
\makeatother
\begin{document}
\begin{tikzpicture}[dirtree]
\node {Maria}   
    child { node {Fuu}
        child { node {Lii} 
            child { node {Lee}
                child { node {Loo} }
                child { node {Luu} }
            }
            child { node {Overlap} 
                child { node { Kim} }
                child { node { Jou} }
            }
        }
        child { node {Long text here}           
        }
    }
    child { node {Foo} };
\end{tikzpicture}
\\ \\
\begin{tikzpicture}[dirtreemid]
\node {Maria}   
    child { node {Fuu}
        child { node {Lii} 
            child { node {Lee}
                child { node {Loo} }
                child { node {Luu} }
            }
            child { node {Overlap} 
                child { node { Kim} }
                child { node { Jou} }
            }
        }
        child { node {Long text here}           
        }
    }
    child { node {Foo} };
\end{tikzpicture}
\end{document}'

And for the reference image I get with the above code. What I'd like to have is the node indentation of the first image without overlapping of nodes. images gotten with the example code

Any help is greatly appreciated!

6

I would do this using forest because it is a lot more flexible and powerful than the other options. In particular, it makes it possible to construct the tree using much more concise code, with less need for definitional acrobatics.

EDIT

In light of the additional desiderata specified in the comment, this is edited to satisfy two conditions:

  1. a new style is used to put all nodes in a given level on the same tier, thus ensuring constant indentation;
  2. l is specified to control the distance between the levels (currently set to 15pt - adjust as required).

The edge path has been adjusted accordingly, and an inner sep specified to keep things compact without being too squashed. Again, these can be further modified according to your requirements.

\documentclass[tikz,varwidth,border=5pt,multi]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{forest}
\begin{document}
\forestset{
  my tier/.style={% align all nodes on a given level
    tier/.wrap pgfmath arg={level##1}{level()},
  },
}
\begin{forest}
  for tree={
    grow'=0,
    child anchor=west,
    parent anchor=south,
    anchor=west,
    calign=first,
    s sep+=-5pt,
    inner sep=2.5pt,
    edge path={
      \noexpand\path [draw, \forestoption{edge}]
      (!u.south west) +(7.5pt,0) |- (.child anchor)\forestoption{edge label};
    },
    before typesetting nodes={
      if n=1{
        insert before={[, phantom, my tier]},
      }{},
    },
    my tier,
    fit=band,
    before computing xy={% change the value of l to alter the distance between levels
      l=15pt,
    },
  }
  [Maria
    [Fuu
      [Lii
        [Lee
          [Loo]
          [Luu]
        ]
        [Overlap
          [Kim]
          [Jou]
        ]
      ]
      [Long text here]
    ]
    [Foo]
  ]
\end{forest}
\end{document}

forest family

  • Thank you for the suggestion. I tried the forest package, but I have trouble aligning the child nodes. I would need the child nodes to be intended the same amount in each level. In the picture it means, that Loo, Luu, Kim, and Jou should be horizontally the same distance from left side of the picture. Another alignment problem is that I need to have child node aligned just couple cm right from the parent node, because the parent node text is quite long. Sorry for not being more specific in my original question. – Tapani Jan 3 '15 at 13:51
  • @Tapani I've edited the code above, and indicated some further ways in which you might tweak things if required. – cfr Jan 3 '15 at 19:12
5

Since the y distance is set to -0.5cm in the dirtree@growth definitin globally (at line 17), one could change the global setting t0 -1cm in this case or adjust manually at those overlapping nodes Overlay, Long text here and Foo via yshift=xx cm syntax, as shown here. This is because manual setting is a local changes, making the resulting image compact.

enter image description here

Code

\documentclass[11pt,a4paper]{report}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\makeatletter
\newcount\dirtree@lvl
\newcount\dirtree@plvl
\newcount\dirtree@clvl
\def\dirtree@growth{%
  \ifnum\tikznumberofcurrentchild=1\relax
  \global\advance\dirtree@plvl by 1
  \expandafter\xdef\csname dirtree@p@\the\dirtree@plvl\endcsname{\the\dirtree@lvl}
  \fi
  \global\advance\dirtree@lvl by 1\relax
  \dirtree@clvl=\dirtree@lvl
  \advance\dirtree@clvl by -\csname dirtree@p@\the\dirtree@plvl\endcsname
  \pgf@xa=1cm\relax
  \pgf@ya=-0.5cm\relax   % <--- here
  \pgf@ya=\dirtree@clvl\pgf@ya
  \pgftransformshift{\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
  \ifnum\tikznumberofcurrentchild=\tikznumberofchildren
  \global\advance\dirtree@plvl by -1
  \fi
}

\tikzset{
  dirtree/.style={
    growth function=\dirtree@growth,
    growth parent anchor=south west,
    parent anchor=south west,
    every node/.style={anchor=north},
    every child node/.style={anchor=west},
    edge from parent path={([xshift=2ex] \tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)},
    growth function=\dirtree@growth,
    every node/.style={anchor=north},
    every child node/.style={anchor=west},
    edge from parent path= {([xshift=2ex]\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)},
  }
}
\tikzset{
  dirtreemid/.style={
    growth function=\dirtree@growth,
    every node/.style={anchor=north},
    every child node/.style={anchor=west},
    edge from parent path={(\tikzparentnode\tikzparentanchor) |- (\tikzchildnode\tikzchildanchor)},
  }
}
\makeatother
\begin{document}
\begin{tikzpicture}[dirtree]   %
\node {Maria}   
    child { node[] {Fuu}
        child { node {Lii} 
            child { node {Lee}
                child { node {Loo} }
                child { node {Luu} }
            }
            child {node[yshift=-0.3cm] {Overlap}
                child { node { Kim} }
                child { node { Jou} }
            }
        }
        child {node[yshift=-0.8cm]  {Long text here}           
        }
    }
    child { node[yshift=-1cm]  {Foo} };
\end{tikzpicture}
\\ 
\begin{tikzpicture}[dirtreemid]
\node {Maria}   
    child { node {Fuu}
        child { node {Lii} 
            child { node {Lee}
                child { node {Loo} }
                child { node {Luu} }
            }
            child { node {Overlap} 
                child { node { Kim} }
                child { node { Jou} }
            }
        }
        child { node {Long text here}           
        }
    }
    child { node {Foo} };
\end{tikzpicture}
\end{document}
  • Thanks for the suggestion. The yshift command works, although it kind of defeats the purpose of automatically laying out the structure :). Adjusting globally the y distance makes the resulting image too tall (because I have 55 nodes in the biggest family tree) and doesn't prevent some inconsistencies with y distances between nodes. – Tapani Jan 3 '15 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.