# How to draw big circles around selected nodes of a tree with tikz?

I have drawn the following tree using tikz with the following code.

My question is: How can I draw one big circle enclosing all the „A“ nodes, one for all „B“ nodes and so on (maybe with different colours)?

I hope it is no problem that the circles will intersect one another sometimes.

Here's the code:

\documentclass[landscape]{article}
\usepackage[a4paper,left=1cm,right=1cm,top=2cm,bottom=2cm,bindingoffset=5mm]{geometry}
\usepackage{tikz}
\usepackage{tikz-qtree}
\makeatletter

\let\old@@children\@@children
\def\@@children{\futurelet\my@next\my@@children}
\def\my@@children{%
\ifx\my@next\missing\else
\expandafter\@gobble
\fi
\expandafter\old@@children}

\makeatother

\newcommand{\missing}{ \edge[draw=none]; {} }
%intended usage inside tikzpicture enviornment:
%\Tree  [.3  1
%               \missing ]
%To producce the same result as code below but
%it gave me an error:
%! Undefined control sequence.
%\missing -> \edge
%                  [draw=none]; {}

\begin{document}

\begin{tikzpicture}[level distance=30pt,sibling distance=5pt]
\Tree
[.$M$
\edge node[auto=right]{1};
[.$L$
\edge node[auto=right]{1};
[.$K$
\edge[dotted];
[.$J$
\edge node[auto=right]{1};
[.$H$
\edge node[auto=right]{2};
[.$G$
\edge node[auto=right]{1};
[.$G$
\edge node[auto=right]{1};
[.$B,G$
\edge node[auto=right]{1};
[.$B$
\edge node[auto=right]{1};
[.$A,B$
\edge node[auto=right]{1};
[.$A$
\edge node[auto=right]{1};
[.$A$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
\edge node[auto=left]{2};
[.$A$
\edge node[auto=left]{2};
[.$A$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
]
]
\edge node[auto=left]{2};
[.$B$
\edge node[auto=left]{2};
[.$B,C$
\edge node[auto=right]{1};
[.$C$
\edge node[auto=right]{1};
[.$C$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
\edge node[auto=left]{2};
[.$C$
\edge node[auto=left]{2};
[.$C$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
]
]
]
]
\edge node[auto=left]{2};
[.$G$
\edge node[auto=left]{2};
[.$D,G$
\edge node[auto=right]{1};
[.$D$
\edge node[auto=right]{1};
[.$D,E$
\edge node[auto=right]{1};
[.$E$
\edge node[auto=right]{1};
[.$E$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
\edge node[auto=left]{2};
[.$E$
\edge node[auto=left]{2};
[.$E$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
]
]
\edge node[auto=left]{2};
[.$D$
\edge node[auto=left]{2};
[.$D,F$
\edge node[auto=right]{1};
[.$F$
\edge node[auto=right]{1};
[.$F$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
\edge node[auto=left]{2};
[.$F$
\edge node[auto=left]{2};
[.$F$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]
]
]
]
]
]
]
]
]
]
]
\end{tikzpicture}
\end{document}


Here's the image:

Thanks for the help!

• Can't you use a regular TikZ node with circle, draw where you want the circles? – cfr Mar 9 '16 at 23:05
• \begin{tikzpicture}[every node/.style=circle]... – John Kormylo Mar 9 '16 at 23:21
• Maybe some clarification is needed. I was assuming that the goal was to have one big circle enclosing all the „A“ nodes, one for all „B“ nodes and so on. Something the fit library can do, but I'm not sure how to do it neatly in this case. – wrtlprnft Mar 10 '16 at 8:32
• Yes, the goal was to have one big circle enclosing all the „A“ nodes, one for all „B“ nodes and so on...thanks for your comment...I edited the question...sorry to the answerers for this misunderstanding... – Bernhard Boehmler Mar 10 '16 at 9:58
• The nodes with precisely the content A or the nodes containing A? – cfr Mar 10 '16 at 17:14

This is straightforward to do with forest. I assume that with your original code, you would need to name the nodes you want to circle and then draw a circle around them, though I'm not sure. With forest, you can automatically collect nodes with particular content into a register which you then use as the basis for the circle. As mentioned in comments, the fit library is the way to go here.

\documentclass[tikz,multi,border=10pt]{standalone}
\usepackage{forest}
\usetikzlibrary{fit}
\begin{document}
\begin{forest}
declare toks register={A nodes},
declare toks register={B nodes},
declare toks register={C nodes},
declare toks register={D nodes},
A nodes={},
B nodes={},
C nodes={},
D nodes={},
for tree={%
math content,
parent anchor=children,
child anchor=parent,
if={level()<2}{%
edge label=1,
}{%
if={(n==1)&&(n("!u")==1)}{%
edge label=1,
}{%
edge label=2,
},
}
},
before typesetting nodes={%
where edge label={1}{%
edge label/.wrap value={node [auto,swap,midway] {#1}},
}{%
edge label/.wrap value={node [auto,midway] {#1}},
},
where content={A}{% pick all nodes with the content "A"
+A nodes/.wrap pgfmath arg={(#1)}{name()},% add to register 'A nodes'
}{%
if content={D}{% pick all nodes  with content "D"
+D nodes/.wrap pgfmath arg={(#1)}{name()},% add to register 'D nodes'
}{%
if content={B}{% pick all nodes with content "B"
+B nodes/.wrap pgfmath arg={(#1)}{name()},% add to register 'B nodes'
}{%
if content={C}{% pick all nodes with content "C"
+C nodes/.wrap pgfmath arg={(#1)}{name()},% add to register 'C nodes'
}{}
}
}
},
},
before packing={%
for tree={%
tier/.wrap pgfmath arg={tier #1}{level()},
},
for root={%
tikz+/.wrap pgfmath arg={% draw around all nodes in the 'A nodes' register
\node [draw=red, circle, fit=#1] {};
}{A_nodes},
tikz+/.wrap pgfmath arg={% draw around all nodes in the 'B nodes' register
\node [draw=green, circle, fit=#1] {};
}{B_nodes},
tikz+/.wrap pgfmath arg={% draw around all nodes in the 'C nodes' register
\node [draw=magenta, circle, fit=#1] {};
}{C_nodes},
tikz+/.wrap pgfmath arg={% draw around all nodes in the 'D nodes' register
\node [draw=blue, circle, fit=#1] {};
}{D_nodes},
}
}
[M
[L
[K
[J, edge={dotted}, edge label={}
[H
[G, edge label=2
[G
[{B,G}
[B
[{A,B}
[A
[A
[...]
[...]
]
]
[A
[A
[...]
[...]
]
]
]
]
[B
[{B,C}
[C
[C
[...]
[...]
]
]
[C
[C
[...]
[...]
]
]
]
]
]
]
[G
[{D,G}
[D
[{D,E}
[E
[E
[...]
[...]
]
]
[E
[E
[...]
[...]
]
]
]
]
[D
[{D,F}
[F
[F
[...]
[...]
]
]
[F
[F
[...]
[...]
]
]
]
]
]
]
]
]
]
]
]
]
\end{forest}
\end{document}


Note that I do not find the results aesthetically pleasing as the size of the circles makes a mess of the tree. However, you explicitly said that you wanted overlapping circles and I can't think of any non-messy result you might have in mind. So hopefully this is of some use.

I would recommend loading shapes.geometric along with fit and using the ellipse shape rather than circle for the fitting nodes:

To do this, just change the line

\usetikzlibrary{fit}


to

\usetikzlibrary{fit,shapes.geometric}


and use the following modified code in before packing={}:

  before packing={%
for tree={%
tier/.wrap pgfmath arg={tier #1}{level()},
},
for root={%
tikz+/.wrap pgfmath arg={%
\node [draw=red, ellipse, fit=#1] {};
}{A_nodes},
tikz+/.wrap pgfmath arg={%
\node [draw=green, ellipse, fit=#1] {};
}{B_nodes},
tikz+/.wrap pgfmath arg={%
\node [draw=magenta, ellipse, fit=#1] {};
}{C_nodes},
tikz+/.wrap pgfmath arg={%
\node [draw=blue, ellipse, fit=#1] {};
}{D_nodes},
}
}


Originally, the question asked for 'circleS' and I understood this as wanting individual circles around the various nodes. Since the code might be useful to somebody who really does want that, I leave it below.

You can use a node with standard TikZ options circle, draw within the tree, just as you do on the edges. For example:

...

\edge node[auto=left]{2};
[.\node[circle,draw]{$A$};
\edge node[auto=left]{2};
[.$A$
\edge node[auto=right]{1};
{$...$}
\edge node[auto=left]{2};
{$...$}
]
]

...


And you can add any other TikZ options you please - coloured border, text or filling, for example - in the usual ways.

If forest is an option, you could probably automatically detect all the A nodes etc. and format them appropriately. (You probably couldn't just circle the A in A,B, but you could circle A,B along with the As if you wished - or not. At least, circling just the A automatically would be more trouble than it would be worth, I think.)

Here's an example which draws and fills circles for all nodes with the content A (red), B (green) or C (magenta); draws and fills a box for all nodes whose content contains D (blue/cyan), and highlights a node and all of its ancestors, including the edges drawn between them (blue). It also largely automates the content and location of the edge labels, while showing how to override this where necessary.

\documentclass[tikz,multi,border=10pt]{standalone}
\usepackage{forest}
\begin{document}
\begin{forest}
/tikz/my shape/.style={%
inner color=#1!5,
outer color=#1!20,
draw=#1,
thick,
},
/tikz/my circle/.style={%
my shape=#1,
circle,
},
for tree={%
math content,
parent anchor=children,
child anchor=parent,
if={level()<2}{%
edge label=1,
}{%
if={(n==1)&&(n("!u")==1)}{%
edge label=1,
}{%
edge label=2,
},
}
},
before typesetting nodes={%
where edge label={1}{%
edge label/.wrap value={node [auto,swap,midway] {#1}},
}{%
edge label/.wrap value={node [auto,midway] {#1}},
},
where content={A}{% pick all nodes with the content "A"
my circle=red,
}{%
if={instr("D",content())}{% pick all nodes containing "D"
my shape=blue!50!cyan,
}{%
if content={B}{% pick all nodes with content "B"
my circle=green!75!black,
}{%
if content={C}{% pick all nodes with content "C"
my circle=magenta,
}{}
}
}
},
},
before packing={%
for tree={%
tier/.wrap pgfmath arg={tier #1}{level()},
}
}
[M
[L
[K
[J, edge={dotted}, edge label={}
[H
[G, edge label=2
[G
[{B,G}
[B
[{A,B}
[A
[A
[...]
[...]
]
]
[A
[A
[...]
[...]
]
]
]
]
[B
[{B,C}
[C
[C
[...]
[...]
]
]
[C
[C
[...]
[...]
]
]
]
]
]
]
[G
[{D,G}
[D
[{D,E}
[E
[E
[...]
[...]
]
]
[E
[E
[...]
[...]
]
]
]
]
[D
[{D,F}
[F
[F
[...]
[...]
]
]
[F
[F
[..., for current and ancestors={blue, edge+=blue} % highlight this node and all of its ancestors
]
[...]
]
]
]
]
]
]
]
]
]
]
]
]
\end{forest}
\end{document}


• Thank you very much for your clear, detailed and very nice answer! – Bernhard Boehmler Apr 11 '16 at 0:58