9

I am trying to build a tree (the theme is argumentation theory, where arguments attack and defend each other) in Tikz but after a few levels down the tree, nodes are placed on top of each other or in a way that the arcs to their parents cross over each other.

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{arrows}
\tikzset{
  every node/.style={minimum size=4mm, inner sep=0.5mm, font=\sffamily},
  level 1/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 2/.style={every child/.style={edge from parent/.style={draw,green}}},
  level 3/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 4/.style={every child/.style={edge from parent/.style={draw,green}}},
  level 5/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 6/.style={every child/.style={edge from parent/.style={draw,green}}},
  def/.style={circle,thick,solid,draw=green!50,fill=green!20},
  att/.style={circle,thick,solid,draw=red!50,fill=red!20}
}
\begin{document}

\begin{tikzpicture}[<-,>=stealth', semithick]

  \node[def, label=east:defense] {}
    child[level distance=11mm] { node[att, label=east:attack] {}
      child {node[def, label=east:defense] {}
        child { node[att, label=east:attack] {} }
        child { node[att, label=east:attack] {} }
      }
      child {node[def, label=east:defense] {} 
        child {node[att, label=east:attack] {}}
        child {node[att, label=east:attack] {}}
      }
      child {node[def, label=east:defense] {}
        child {node[att, label=east:attack] {} }
        child {node[att, label=east:attack] {} }
        child {node[att, label=east:attack] {} }
      }
  }; 
\end{tikzpicture}

\end{document}

The result is the following:

arcs crossing over each other

As you can see, in the bottom layer, the arcs of the two nodes in the middle inevitably cross over each other. In addition, the two nodes after the first one in the bottom layer are placed on top of each other.

Is there a "adjust the distance between the nodes however you want so that the arcs between them don't cross and the nodes don't appear on top of each other"-command that I can use? Thank you very much for all the help and I hope this isn't a duplicate question as I couldn't find a similar one!

  • 1
    Can't you just manually set a sibling distance? Or do you mean that you want the sibling distance to be set automatically? And welcome to TeX.SX! – Adam Liter Apr 30 '14 at 19:48
  • Welcome to TeX.SE. – Peter Grill Apr 30 '14 at 19:58
  • Thank you for the warm welcome! I have tried using sibling distance but it seems that nothing changes when I do (maybe I am not using it properly? - I have to admit I am a Latex beginner). – George Flourentzos Apr 30 '14 at 21:48
8

This is a good opportunity to illustrate the power of the forest package; the labeling and the coloring are automatically done base on a conditional test for the level:

\documentclass{article}
\usepackage{forest}

\begin{document}

\begin{forest}
for tree={
  edge={<-,>=latex},
  l sep=1cm,
  circle,
  minimum size=12pt,
  anchor=west,
  where={iseven(level)}
    {edge={green},
      draw=green!50,
      fill=green!20,
      edge label={node[anchor=west,right,font=\sffamily,xshift=7pt,yshift=1pt]{\color{black}defense}}
    }
    {edge={red},
      draw=red!50,
      fill=red!20,
      edge label={node[anchor=west,font=\sffamily,xshift=7pt,yshift=1pt]{\color{black}attack}}
    },
  if={level>1}
    {s sep=1.3cm}
    {}
}
[,tikz={\node[pos=0,font=\sffamily,anchor=west,xshift=12pt,yshift=1pt]{defense};}
  [,s sep=1.85cm
    [ [] [] ]
    [ [] [] ]
    [ [] [] [] ]
  ]
]
\end{forest}

\end{document}

enter image description here

Since the labeling and coloring are automatically done based on a conditional test for the node level, the same preamble for tree specification applied to

[,tikz={\node[pos=0,font=\sffamily,anchor=west,xshift=12pt,yshift=1pt]{defense};}
  [,s sep=1.85cm
    [ [ [] [] ] [] ]
    [ [ [] [] ] [] ]
    [ [ [] [] ] [] [ [] [] ] ]
  ]
]

will now produce

enter image description here

  • How can I add a label per node using the square brackets syntax? (the label needs to be outside the node so I can't use [.mylabel]) – George Flourentzos May 1 '14 at 11:36
  • @GeorgeFlourentzos I am not sure I understand your question correctly. Where should this label appear? Next to the node? Next to the edge? My example code already shows two possibilities to do this using either [ ,edge label={node[xshift=7pt]{text}}] or [ ,tikz={\node[xshift?15pt]{text};}]. Changing the options for the node you can place the label at the desired location. – Gonzalo Medina May 1 '14 at 19:15
  • Your example code labels nodes with "attack" or "defense" automatically in the for tree, but I would like to label each node differently. I admit I should have named the nodes in my example differently because I probably gave the wrong impression. I missed the comma in [ ,<code for label>] when I was trying to label nodes individually, but the first code snippet in your comment above made it crystal clear! Thank you once again! You've been very helpful! – George Flourentzos May 1 '14 at 19:36
7

You can set a different sibling distance for each level

\documentclass[tikz,margin=5mm]{standalone}
\usetikzlibrary{arrows}
\tikzset{
  every node/.style={minimum size=4mm, inner sep=0.5mm, font=\sffamily},
  level 1/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 2/.style={every child/.style={edge from parent/.style={draw,green}},
    sibling distance=12em},
  level 3/.style={every child/.style={edge from parent/.style={draw,red}},
    sibling distance=5em},
  def/.style={circle,thick,draw=green!50,fill=green!20,label={right:defense}},
  att/.style={circle,thick,draw=red!50,fill=red!20,label={#1:attack}},
  att/.default=right
}
\begin{document}

\begin{tikzpicture}[<-,>=stealth']
  \node[def] {}
    child[level distance=11mm] { node[att={[yshift=1mm]right}] {}
      child {node[def] {}
        child { node[att] {} }
        child { node[att] {} }
      }
      child {node[def] {} 
        child {node[att] {}}
        child {node[att] {}}
      }
      child {node[def] {}
        child {node[att] {} }
        child {node[att] {} }
        child {node[att] {} }
      }
  }; 
\end{tikzpicture}
\end{document}

enter image description here


Or with the graphdrawing library (needs pgf/tikz Version 3.0.0 and LuaLaTeX):

\documentclass[margin=5mm,tikz]{standalone}
\usetikzlibrary{graphs,graphdrawing}
\usegdlibrary{trees}
\usetikzlibrary{arrows}
\tikzset{
  every node/.style={minimum size=4mm, inner sep=0.5mm},
  def/.style={circle,thick,solid,draw=green!50,fill=green!20,label={right:defense}},
  att/.style={circle,thick,solid,draw=red!50,fill=red!20,label={#1:attack}},
  att/.default=right
}

\begin{document}
\begin{tikzpicture}[>=stealth',font=\sffamily]
  \graph[tree layout,empty nodes]{
    {[trie]a[def]<-[red]a[att={[yshift=1mm]right}]<-[green]{[nodes=def]a,b,c},},
    {[nodes=att,edges=red,trie,sibling distance=\widthof{attack\qquad}]
      a a a<-{a,b},
      a a b<-{a,b},
      a a c<-{a,b,c},
    }
  };
\end{tikzpicture}
\end{document}

enter image description here

3

Adding a sibling distance will spread things out a bit.

\documentclass{standalone}
\usepackage{tikz}

\usetikzlibrary{arrows}
\tikzset{
  every node/.style={minimum size=4mm, inner sep=0.5mm, font=\sffamily},
  level 1/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 2/.style={every child/.style={edge from parent/.style={draw,green}}},
  level 3/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 4/.style={every child/.style={edge from parent/.style={draw,green}}},
  level 5/.style={every child/.style={edge from parent/.style={draw,red}}},
  level 6/.style={every child/.style={edge from parent/.style={draw,green}}},
  def/.style={circle,thick,solid,draw=green!50,fill=green!20},
  att/.style={circle,thick,solid,draw=red!50,fill=red!20}
}
\begin{document}

\begin{tikzpicture}[<-,>=stealth', semithick,sibling distance=10em]
  \node[def, label=east:defense] {}
    child[level distance=11mm] { node[att, label=east:attack] {}
      child {node[def, label=east:defense] {}
        child { node[att, label=east:attack] {} }
        child { node[att, label=east:attack] {} }
      }
      child {node[def, label=east:defense] {} 
        child {node[att, label=east:attack] {}}
        child {node[att, label=east:attack] {}}
      }
      child {node[def, label=east:defense] {}
        child {node[att, label=east:attack] {} }
        child {node[att, label=east:attack] {} }
        child {node[att, label=east:attack] {} }
      }
  }; 
\end{tikzpicture}
\end{document}

enter image description here

  • Even though it definitely looks clearer than what I have, the main problem still remains in that, at the bottom level, the arcs of the nodes in the middle (connecting them to their respective parents) still cross, and the two nodes after the first one on the left are placed on top of each other (it looks like one node with two parents). Is there something that could be done? Thanks! – George Flourentzos Apr 30 '14 at 22:25

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.