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!

3 Answers3

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

Gonzalo Medina
  • 505,128
  • 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 01 '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 01 '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 01 '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

esdd
  • 85,675
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

erik
  • 12,673
  • 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