[Tex/LaTex] Step-by-step revealing of tikz-tree using opacity trick and overlays in beamer

beameroverlaystikz-trees

I am using the very elegant method from user Daniel described here to try and reveal my tikz-tree gradually.
The brief idea is that the tree is always fully drawn to avoid "jumpy" nodes and make their coordinates available even if they are "invisible", but that the opacity is set to 0 on those nodes that are not supposed to be seen yet.

This is how my complete tree should look like after the reveal (I apologize in advance for the miserable quality of my phone's camera):

Complete tree should look like this

Here is my code:

\documentclass{beamer}
\usepackage{tikz}
\usepackage[utf8]{inputenc}
\usetikzlibrary{trees}

% Daniel's proposal for "uncovering" parts of a tikz-tree %
\tikzset{
  invisible/.style={opacity=0},
  visible on/.style={alt=#1{}{invisible}},
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
  },
}    

\begin{document}
\begin{frame}
\begin{tikzpicture}[
nor/.style={circle,thick,solid,draw=black,fill=none,inner sep=0.5mm, minimum size=5mm},
acc/.style={circle,thick,solid,draw=green!50!black,fill=green!20,inner sep=0.5mm, minimum size=5mm},
rej/.style={circle,thick,solid,draw=red!50,fill=red!20,inner sep=0.5mm, minimum size=5mm},
level 1/.style={every child/.style={edge from parent/.style={dashed,draw,nearly opaque}} },
level 2/.style={sibling distance=19mm,every child/.style={edge from parent/.style={solid,draw}}},
level 3/.style={sibling distance=8mm,every child/.style={edge from parent/.style={dashed,draw,nearly opaque}} },
semithick]

\node[draw=none] (root) {}
  child[level distance=12mm,visible on=<1->] { node[nor] {$x$}
    child[visible on=<2->] {node[acc] {$e_1(x)$} }
    child[visible on=<2->] {node[nor] {$e_2(x)$}
      child[visible on=<6->] child[visible on=<6->] }
    child[visible on=<2->] {node[rej] {$e_3(x)$} }
    child[visible on=<2->] {node[nor] {$e_4(x)$}
      child[visible on=<6->] child[visible on=<6->] child[visible on=<6->] }
  };
\end{tikzpicture}
\end{frame}
\end{document}

The 4 sibling nodes on level 2 are correctly hidden, including their solid edges to/from the (x) node. As expected, they show up in the second slide and then stay visible.

But the dashed edges at the bottom of the tree are shown since the very first slide – even though the leaf nodes are set to be visible from slide 6 onwards.

Why is this happening? This way of doing things was accepted as an answer and received a lot of praise in the original question, so it certainly works. It's just partially working for me, since I seem to have a wrong understanding of how child inherits its style to all of the nodes underneath it… or perhaps it's a problem of the levels being styled manually as well (even though this doesn't seem to affect level 2).

Ideas on how to fix this?

Best Answer

Preface

Due to MHaaZ comment I tried to investigated what was really wrong with his code and I've found that my orginial answer was not correct enough. I'll leave it here for the records but I prefer to write a new one.

New Answer

The only problem with your code is using nearly opaque option in level 1 and level 3 style definitions. I still don't understand very well how visible on works but it sets opacity=0 for all invisible pieces and nearly opaque changes this initial value.

I can provide two solutions. First one consist in being sure that visible on option is applied after setting opacity. This way edges or nodes will keep it's opacity when they are visible. Something like

level 1/.style={every child/.style={edge from parent/.style={dashed,draw,nearly opaque, visible on=<2->}}},

will solve the problem (look at original answer code below).

If just want nearly opaque option to fade dashed lines, another solution would be to whiten them. I think dashed, draw=black!30 or similar will have a similar effect and avoid conflicts with visible on. Your code with this second solution will be:

\documentclass{beamer}
\usepackage{tikz}
\usepackage{inputenc}[utf8]
\usetikzlibrary{trees}

% Daniel's proposal for "uncovering" parts of a tikz-tree %
\tikzset{
  invisible/.style={opacity=0},
  visible on/.style={alt=#1{}{invisible}},
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
  },
}    

\begin{document}
\begin{frame}
\begin{tikzpicture}[
nor/.style={circle,thick,solid,draw=black,fill=none,inner sep=0.5mm, minimum size=5mm},
acc/.style={circle,thick,solid,draw=green!50!black,fill=green!20,inner sep=0.5mm, minimum size=5mm},
rej/.style={circle,thick,solid,draw=red!50,fill=red!20,inner sep=0.5mm, minimum size=5mm},
level 1/.style={every child/.style={edge from parent/.style={dashed,draw=black!30}} },
level 2/.style={sibling distance=19mm,every child/.style={edge from parent/.style={solid,draw=black}}},
level 3/.style={sibling distance=8mm,every child/.style={edge from parent/.style={dashed,draw=black!30}} },
semithick]

\node[draw=none] (root) {}
  child[level distance=12mm,visible on=<1->] { node[nor] {$x$}
    child[visible on=<2->] {node[acc] {$e_1(x)$} }
    child[visible on=<2->] {node[nor] {$e_2(x)$}
      child[visible on=<6->] child[visible on=<6->] }
    child[visible on=<2->] {node[rej] {$e_3(x)$} }
    child[visible on=<2->] {node[nor] {$e_4(x)$}
      child[visible on=<6->] child[visible on=<6->] child[visible on=<6->] }
  };
\end{tikzpicture}
\end{frame}
\end{document}

Last frame will look like:

enter image description here

Original Answer

A node and its corresponding edge from parent can be drawn with different actions, so you can (or have to) apply visible on option to each particular edge. Even applying visible on to a particular level style, you can change it inside a particular node definition.

\documentclass{beamer}
\usepackage{tikz}
\usepackage[utf8]{inputenc}
\usetikzlibrary{trees}

% Daniel's proposal for "uncovering" parts of a tikz-tree %
\tikzset{
  invisible/.style={opacity=0},
  visible on/.style={alt=#1{}{invisible}},
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
  },
}    

\begin{document}
\begin{frame}
\begin{tikzpicture}[
ball/.style={circle, thick, solid,inner sep=0.5mm, minimum size=5mm},
nor/.style={ball,draw=black,fill=none},
acc/.style={ball,draw=green!50!black,fill=green!20},
rej/.style={ball,draw=red!50,fill=red!20},
level 1/.style={every child/.style={edge from parent/.style={dashed,draw,nearly opaque, visible on=<2->}}},
level 2/.style={sibling distance=19mm,every child/.style={edge from parent/.style={solid,draw,visible on=<2->}}},
level 3/.style={sibling distance=8mm,every child/.style={edge from parent/.style={dashed,draw,nearly opaque, visible on=<5->}} },
semithick]

\node[draw=none] (root) {}
  child[level distance=12mm,visible on=<1->] { node[nor] {$x$}
    child[visible on=<2->] {node[acc] {$e_1(x)$} }
    child[visible on=<3->] {node[nor] {$e_2(x)$} edge from parent[red, visible on=<4->]
      child[visible on=<6->] child[visible on=<6->] }
    child[visible on=<2->] {node[rej] {$e_3(x)$} }
    child[visible on=<3->] {node[nor] {$e_4(x)$}
      child[visible on=<6->] {} child[visible on=<6->] child[visible on=<6->] }
  };
\end{tikzpicture}
\end{frame}
\end{document}

enter image description here