6

I am building a tree structure in tikz and am following this texample, which suggests adding styles for the children according to their depth in the tree (first, second and so on). The purpose is that each level needs to adjust the level distance attribute. What I would like to do is use \foreach like so:

 \foreach \x / \y in {first/1,second/2,third/3,fourth/4,fifth/5,sixth/6,seventh/7,eight/8,ninth/9}
 {\tikzstyle{\x}=[level distance=\y*6 em]};

Or something of that sort, to set the distance for each level to a multiple of 6. The factor should depend on the level. I have tried to research how to use arithmetic in \foreach and came up with \pgfmathparse{\y * 6}\pgfmathresult to actually compute the number. So what I have is

 \foreach \x / \y in {first/1,second/2,third/3,fourth/4,fifth/5,sixth/6,seventh/7,eight/8,ninth/9}
 {\tikzstyle{\x}=[level distance=\pgfmathparse{\y * 6}\pgfmathresult em]};

And this compiles, but no styles are actually set. If I attempt to reference e.g. first, I get the Error: I do not know the key '/tikz/first'. Maybe this has something to do with the order of macro expansion or some such magic.

Here is an MWE

\documentclass{scrartcl}
\usepackage{tikz}
\usepackage[utf8]{inputenc}
\begin{document}

\usetikzlibrary{trees,calc}
\begin{tikzpicture}[
      work package/.style={draw,rectangle,text width=3cm},
      grandchild/.style={grow=down,
      edge from parent path={(\tikzparentnode.west) -- ++(-1em,0) |- ($(\tikzparentnode.south west) + (-1em,0)$) |- (\tikzchildnode.west)}},
      first/.style={level distance=6ex},
      second/.style={level distance=14ex},
      third/.style={level distance=22ex},
      fourth/.style={level distance=30ex},
      fifth/.style={level distance=38ex},
      level 1/.style={sibling distance=4cm,level distance=2cm}
   ]   
   % \foreach \x / \y in {first/1,second/2,third/3,fourth/4,fifth/5,sixth/6,seventh/7,eight/8,ninth/9}
   % {\tikzstyle{\x}=[level distance=\pgfmathparse{\y * 6}\pgfmathresult em]};
   % Parents
   \coordinate
   node[work package, text centered] {Client-Server-System für Versicherung}
   [edge from parent fork down]
   % Children and grandchildren
   child{node[work package] {Phase 1}
      child[grandchild,first] {node[work package] {A: Funktionen erarbeiten}}
      child[grandchild,second] {node[work package] {B: Funktionen einteilen}}
      child[grandchild,third] {node[work package] {C: Schnittstellen zu Fremdsystemen}}
      child[grandchild,fourth] {node[work package] {D: Datenbankentwurf}}
      child[grandchild,fifth] {node[work package] {E: GUI-Prototyp entwickeln}}
   }   
   child{node[work package] {Phase 2}};

\end{tikzpicture}
\end{document}
  • \tikzstyle{\x}={stuff} is equivalent to \pgfkeys{/tikz/\x/.style={stuff}}. Anyway, if you want to put it inside a \foreach lopp you will probably new \pgfextra to turn off the tikz parser. – John Kormylo Nov 1 '14 at 13:25
  • The code in a \foreach loop is executed inside a group and so outside it the styles are not set. – Andrew Stacey Nov 1 '14 at 20:35
  • Ok, any way to fix that? Somehow export them out of their scope? – oarfish Nov 1 '14 at 21:36
2

Keeping close to the OP's code, here is way which uses package xinttools for its \xintForpair loop. The syntax is a bit different from the \foreach one, but the important thing here is that the items are not executed inside groups.

Besides there were other problems in the OP's code inside the \foreach in the way the \pgfmathparse was used, but anyhow it was not needed in the end.

\documentclass{scrartcl}
\usepackage{tikz}
\usepackage[utf8]{inputenc}

\usepackage{xinttools}% for \xintForpair loop 

\begin{document}

\usetikzlibrary{trees,calc}
\begin{tikzpicture}[
      work package/.style={draw,rectangle,text width=3cm},
      grandchild/.style={grow=down,
      edge from parent path={(\tikzparentnode.west) -- ++(-1em,0) |-
        ($(\tikzparentnode.south west) + (-1em,0)$) |-
        (\tikzchildnode.west)}},
% commented-out from OP's code:
      % first/.style={level distance=6ex},
      % second/.style={level distance=14ex},
      % third/.style={level distance=22ex},
      % fourth/.style={level distance=30ex},
      % fifth/.style={level distance=38ex},
      level 1/.style={sibling distance=4cm,level distance=2cm}
   ] 
% This can not work because \foreach items are executed inside groups
%
% besides, the \pgfmathparse should have been done before the \tikzstyle
% and only \pgfmathresult used in level distance key value
% 
% \foreach \x / \y in {first/1,second/2,third/3,fourth/4,fifth/5,sixth/6,seventh/7,eight/8,ninth/9}
% {\tikzstyle{\x}=[level distance=\pgfmathparse{\y * 6}\pgfmathresult em]};
%
% from package xinttools, a looping with a slightly different syntax:
%
   \xintForpair #1#2 in
   {(first,1),(second,2),(third,3),(fourth,4),(fifth,5),(sixth,6),(seventh,7),(eight,8),(ninth,9)} \do
   {\tikzstyle{#1}=[level distance=6*#2 em]}
% (turns out 6*#2 is correctly parsed directly)
%
   % Parents
   \coordinate
   node[work package, text centered] {Client-Server-System für Versicherung}
   [edge from parent fork down]
   % Children and grandchildren
   child{node[work package] {Phase 1}
      child[grandchild,first] {node[work package] {A: Funktionen erarbeiten}}
      child[grandchild,second] {node[work package] {B: Funktionen einteilen}}
      child[grandchild,third] {node[work package] {C: Schnittstellen zu Fremdsystemen}}
      child[grandchild,fourth] {node[work package] {D: Datenbankentwurf}}
      child[grandchild,fifth] {node[work package] {E: GUI-Prototyp entwickeln}}
   }   
   child{node[work package] {Phase 2}};

\end{tikzpicture}
\end{document}

tikz tree with xintForpair

  • I like this answer best since it's closest to what I had in mind. – oarfish Jan 6 '15 at 10:33
2

Or you can do this without a loop :

\documentclass[varwidth,border=50]{standalone}
\usepackage{tikz}
\usetikzlibrary{trees,calc}

\begin{document}
   \begin{tikzpicture}[
         work package/.style={draw,rectangle,text width=3cm},
         grandchild/.style={grow=down,
         edge from parent path={(\tikzparentnode.west) -- ++(-1em,0) |- ($(\tikzparentnode.south west) + (-1em,0)$) |- (\tikzchildnode.west)}},
         child/.style={level distance={(#1*8-2)*1ex}},
         level 1/.style={sibling distance=4cm,level distance=2cm}
      ]
      % Parents
      \coordinate
      node[work package, text centered] {Client-Server-System für Versicherung}
      [edge from parent fork down]
      % Children and grandchildren
      child{node[work package] {Phase 1}
         child[grandchild,child=1] {node[work package] {A: Funktionen erarbeiten}}
         child[grandchild,child=2] {node[work package] {B: Funktionen einteilen}}
         child[grandchild,child=3] {node[work package] {C: Schnittstellen zu Fremdsystemen}}
         child[grandchild,child=4] {node[work package] {D: Datenbankentwurf}}
         child[grandchild,child=5] {node[work package] {E: GUI-Prototyp entwickeln}}
      }
      child{node[work package] {Phase 2}};

   \end{tikzpicture}
\end{document}

enter image description here

EDIT Here is a code using counter for auto-shifting.

  \documentclass[varwidth,border=50]{standalone}
  \usepackage{tikz}
  \usetikzlibrary{trees,calc}

  \newcounter{child}

  \begin{document}
     \begin{tikzpicture}[
           work package/.style={draw,rectangle,text width=3cm},
           grandchild/.style={grow=down,
           edge from parent path={(\tikzparentnode.west) -- ++(-1em,0) |- ($(\tikzparentnode.south west) + (-1em,0)$) |- (\tikzchildnode.west)}},
           grandchild/.append code={\stepcounter{child}\pgfkeysalso{level distance={\thechild*4ex-2ex}}},
           level 1/.style={sibling distance=4cm,level distance=2cm}
        ]
        % Parents
        \coordinate
        node[work package, text centered] {Client-Server-System für Versicherung}
        [edge from parent fork down]
        % Children and grandchildren
        child{node[work package] {Phase 1}
           child[grandchild] {node[work package] {A: Funktionen erarbeiten}}
           child[grandchild] {node[work package] {B: Funktionen einteilen}}
           child[grandchild] {node[work package] {C: Schnittstellen zu Fremdsystemen}}
           child[grandchild] {node[work package] {D: Datenbankentwurf}}
           child[grandchild] {node[work package] {E: GUI-Prototyp entwickeln}}
        }
        child{node[work package] {Phase 2}};

     \end{tikzpicture}
  \end{document}
0

Only because it is a tree... but it does make the tree specification nice and concise... [But I can't figure out how to make it break the lines automatically within the nodes.]

\documentclass[tikz, border=5pt]{standalone}
\usepackage[utf8]{inputenc}
\usepackage{forest}
\begin{document}
  \begin{forest}
    for tree={
      draw,
      text width=3cm,
      align=left,
      edge path={
        \noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(-10pt,0pt) |- (.child anchor)\forestoption{edge label};
      },
      where level=0{
        parent anchor=south,
        l sep+=10pt,
      }{
        where level=1{
          parent anchor=west,
          child anchor=north,
          edge path={
            \noexpand\path [\forestoption{edge}] (!u.parent anchor) -- +(0,-7.5pt) -| (.child anchor)\forestoption{edge label};
          },
        }{
          parent anchor=west,
          child anchor=west,
        },
      },
    }
       [Client-Server-\\System für\\Versicherung, text centered, align=center
         [Phase 1
           [A: Funktionen\\erarbeiten
             [B: Funktionen\\einteilen
               [C: Schnittstellen\\zu Fremdsystemen
                 [D: Datenbanken-\\twurf
                   [E: GUI-Prototyp\\entwickeln
                   ]
                 ]
               ]
             ]
           ]
         ]
         [Phase 2
         ]
       ]
  \end{forest}
\end{document}

forest tree

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.