26

To make it simple, I want to highlight a group of tikz nodes like in the following picture

enter image description here

It was borrowed from the JLatexEditor. I would like to know which Tikz commands I can use to do the job in order to automatize this task for several trees I have to make. It is important to keep the blending effect of colors like in node g. Here is the MWE also borrowed from JLatexEditor:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{arrows,backgrounds,calc,trees}

\begin{document}
\thispagestyle{empty}

\begin{tikzpicture}
\node (f) {f}
    child { node (g) {g}
      child { node (a) {a}
    }
      child { node (b) {b}
    }
  }
    child { node (h) {h}
      child { node (c) {c}
    }
  };
\end{tikzpicture}

\end{document}
ebosi
  • 11,692

2 Answers2

27

The use of the hobby package here leads to a very similar result to the picture posted by the OP:

enter image description here

I was in doubt if posting this answer because it's pretty much the same of the one given in Highlighting some nodes of a TikZ binomial tree, but it could be seen as a better example of use of the hobby package. The point is that in the answer Highlighting some nodes of a TikZ binomial tree several [tension in]s were used, but I saw that the result could be improved by simply adding more points along the curve. This from one hand complicate a bit the path definition, but I think is a good price to pay seeing the result.

The code:

\documentclass[a4paper,11pt]{article}
\usepackage{tikz}
\usetikzlibrary{hobby,backgrounds,calc,trees}

\begin{document}
\begin{tikzpicture}
\node (f) {f}
    child { node (g) {g}
      child { node (a) {a}
    }
      child { node (b) {b}
    }
  }
    child { node (h) {h}
      child { node (c) {c}
    }
  };

  \begin{pgfonlayer}{background}
  \draw[blue,fill=blue,opacity=0.2](f.north) to[closed,curve through={($(f.south west)!0.5!(g.north west)$) .. (g.south west) .. (h.south west) .. (c.south west) .. (c.south east) .. ($(c.north east)!0.5!(h.south east)$) .. (h.east).. ($(h.north east)!0.5!(f.south east)$)}](f.north);
  \draw[red,fill=red,opacity=0.2](g.north) to[closed,curve through={($(g.south west)!0.5!(a.north west)$) .. (a.south west) .. (a.south east) ..(b.south west) .. (b.south east) .. ($(b.north east)!0.5!(g.south east)$) }] (g.north);
  \end{pgfonlayer}
\end{tikzpicture}

\end{document}
  • Woah, that looks really good! Can you combine that with the convex hull approach so you only need to provide the list of nodes that you want enveloped? – Jake Sep 11 '12 at 07:45
  • 1
    Thanks Jake, but the most of the credit should go to Andrew's great package :) Regarding the question: yes, it's really a good idea. I'll have a look as soon as possible! – Claudio Fiandrino Sep 11 '12 at 07:47
  • Your method renders a much better looking output, but I really need the task to be automatized like @Gonzalo Medina did with \convexpath{a,g,b}{8pt}. I'll keep Gonzalo's answer as the accepted one. But I will really love to see a combination of both solutions like @Jake proposes. – Felipe Aguirre Sep 11 '12 at 12:32
  • @Jake: I did a trial, but my bad math background does not helped too much :); I followed exactly your procedure in two directions basically: at first I still adopted the arc to draw the path around a single node (see http://imgur.com/Oy9z3) while in a second moment I tried to remove it (no image uploaded for decency :D). My intuition indeed is that removing the arc path by substituting it in some other manner will help, but I have no idea about it. Should I open a question? – Claudio Fiandrino Sep 12 '12 at 12:57
  • 2
    I vote for opening a question! – Felipe Aguirre Sep 13 '12 at 12:28
  • 2
  • I love this community, thank you for existing! – Felipe Aguirre Sep 15 '12 at 10:35
22

You can use Jake's answer to padded boundary of convex hull and layers:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows,backgrounds,calc,trees}

\pgfdeclarelayer{background}
\pgfsetlayers{background,main}


\newcommand{\convexpath}[2]{
[   
    create hullnodes/.code={
        \global\edef\namelist{#1}
        \foreach [count=\counter] \nodename in \namelist {
            \global\edef\numberofnodes{\counter}
            \node at (\nodename) [draw=none,name=hullnode\counter] {};
        }
        \node at (hullnode\numberofnodes) [name=hullnode0,draw=none] {};
        \pgfmathtruncatemacro\lastnumber{\numberofnodes+1}
        \node at (hullnode1) [name=hullnode\lastnumber,draw=none] {};
    },
    create hullnodes
]
($(hullnode1)!#2!-90:(hullnode0)$)
\foreach [
    evaluate=\currentnode as \previousnode using \currentnode-1,
    evaluate=\currentnode as \nextnode using \currentnode+1
    ] \currentnode in {1,...,\numberofnodes} {
  let
    \p1 = ($(hullnode\currentnode)!#2!-90:(hullnode\previousnode)$),
    \p2 = ($(hullnode\currentnode)!#2!90:(hullnode\nextnode)$),
    \p3 = ($(\p1) - (hullnode\currentnode)$),
    \n1 = {atan2(\y3,\x3)},
    \p4 = ($(\p2) - (hullnode\currentnode)$),
    \n2 = {atan2(\y4,\x4)},
    \n{delta} = {-Mod(\n1-\n2,360)}
  in 
    {-- (\p1) arc[start angle=\n1, delta angle=\n{delta}, radius=#2] -- (\p2)}
}
-- cycle
}

\begin{document}
\thispagestyle{empty}

\begin{tikzpicture}
\node (f) {f}
    child { node (g) {g} 
      child { node (a) {a}
    }
      child { node (b) {b}
    }
  }
    child { node (h) {h}
      child { node (c) {c}
    }
  };
\begin{pgfonlayer}{background}
\fill[red,opacity=0.3] \convexpath{a,g,b}{8pt};
\fill[blue,opacity=0.3] \convexpath{g,f,h,c,h,f}{8pt};
\end{pgfonlayer}
\end{tikzpicture}

\end{document}

enter image description here

Gonzalo Medina
  • 505,128
  • Muchas gracias!! – Felipe Aguirre Sep 10 '12 at 21:02
  • 3
    I found a particularity of your method that I think it is worth signaling in this post. The nodes have to be enumerated in the order of the clockwise direction (As it was stated in Jake's question). Otherwise, it will render a wrong convex hull. So, \convexpath{a,g,b} is correct, but \convexpath{a,b,g} is not. – Felipe Aguirre Sep 11 '12 at 12:58