# How to draw nested nodes?

I want to draw the following png graph generated by the dot program. After some quick research I decided to give a try to matrix nodes. Using it I successfully created the first Pipeline block. Unfortunately when trying to nest the BandPassFilter I reached a compilation error message saying:

alchemy.tex:541: Package pgf Error: You cannot nest pgfmatrix environments, yet.

I am looking here for the right direction to follow in order to draw such graphs. It's worth noting that in this case the depth is only 2 but I need a solution for any depth.

Note: I am not looking for the tikz code drawing this graph but only for help to get started.

-
fit library can draw those rectangles for you. –  percusse Dec 4 '12 at 20:16
@percusse Thanks for the very quick answer. I am going to look at Fit. Just one question, I draw my nodes without the rectangles using for example relative positioning between nodes (below right=of ... for example) and then add the rectangles with fit ? –  Manuel Selva Dec 4 '12 at 20:20
An option with the list of the nodes to be covered e.g. \node[fit=(nodenames) (that) (I want to) (be covered)] {}; is sufficient. But those nodes should be defined beforehand. There are a few examples in the manual. –  percusse Dec 4 '12 at 20:23
Here is a recent tutorial style answer of mine that might help get you stated with the fit library: how to draw a container box in latex around automata?. –  Peter Grill Dec 4 '12 at 20:26
@PeterGrill beautiful tutorial :) I'd vote for a similar answer of yours on this question too :) –  cmhughes Dec 4 '12 at 22:12

Here is a brief tutorial style on dong this kind of diagram. There are numerous way each step can be achieved, and I am just showing one of the ways works. Note that this captures how I go about doing these kind of diagrams but is by no means implying that this is necessarily the best way of going about it, and is aimed at those that are new to tikz.

## 1. Drawing an Ellipse:

Better to not attempt such a diagram until we can at least figure out how to draw the ellipse. Well, luckily this is already built into tikz:

\documentclass[border=2pt]{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\draw [blue, ultra thick] (0, 0) ellipse (1.5cm and 1cm);
\end{tikzpicture}
\end{document}


works great. However, in this case the ellipses have an associated text, so perhaps using a \node would be better:

\node [draw=blue, ultra thick, ellipse] at (0, 0) {text};


The above required the use of \usetikzlibrary{shapes}. And since we have several of these ellipses we really should define a style:

\tikzset{my ellipse/.style={draw=blue, ultra thick, ellipse}}


So, now using \node [my ellipse] at (0, 0) {text}; we get:

Looks like we are ready to start the actual diagram.

## 2. Positioning the Ellipses

First step is to determine how to position the ellipses? The obvious choice to me is to position them using relative placement. But before we can position them, need to be able to draw at least one of them.

Ok, so lets do the first two. We can just place the Int Source node at (0,0):

\node [my ellipse] (Int Source) at (0, 0) {Int Source};


We might as well use the text Int Source to the provide a name of this node (Int Source) to make things easier to read when we reference them. An obvious place to place the duplicate node would be at (Int Source.east):

\node [my ellipse] (Int Source) at (0, 0)            {Int Source};
\node [my ellipse] (duplicate)  at (Int Source.east) {duplicate};


which yields:

Not quit what we were looking for. So, why is the (duplicate) not east of (Int Source) like we specified. Looking closely it seems that the center of the node, (duplicate.center), is indeed placed at (Int Source.east). So, we just need to specify what anchor is to be used. So:

\node [my ellipse, anchor=west] (duplicate)  at (Int Source.east) {duplicate};


gets us something that is at least readable:

Still not there, as we really want to move this a bit more to the right. For this we can either specify apply an xshift=:

\node [my ellipse,anchor=west,xshift=1.0cm] (duplicate) at (Int Source.east) {duplicate};


which moves the node over nicely:

## 3. Making the connections:

Ok, before we place all the ellipses, lets make sure we can connect them. So:

\draw [->] (Int Source.east) -- (duplicate.west);


seems to work fine. But we know that we'll probably want to change all the arrows we'd better define a style for them:

\tikzset{my arrow/.style={-latex, thick}}


Now, \draw [my arrow] (Int Source.east) -- (duplicate.west); yields:

## 4. Placing the other nodes:

Now we can continue on and place the other nodes. For the High Pass Filter node we need to use an yshift to move it up. So, up until now we have:

    \node [my ellipse]                                          (Int Source) at (0, 0) {Int Source};
\node [my ellipse, anchor=west, xshift=1.0cm]               (duplicate)  at (Int Source.east) {duplicate};
\node [my ellipse, anchor=west, xshift=1.0cm, yshift=1.0cm] (High Pass Filter) at (duplicate.east) {High Pass Filter};

\draw [my arrow] (Int Source.east) -- (duplicate.west);


Now that we have placed another node we see some repetition. Perhaps we should just add the anchor=west, xshift=1.0cm to the node style and that would make the code a bit easier to maintain. And for this particular diagram this method of placement seems to be working:

\tikzset{my ellipse/.style={draw=blue, ultra thick, ellipse, anchor=west, xshift=1.0cm}}
\tikzset{my arrow/.style={-latex, thick}}


So, now we continue on and place the other nodes and draw the arrows by connecting the various anchor points:

\documentclass[border=2pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes}

\begin{document}

\tikzset{my ellipse/.style={draw=blue, ultra thick, ellipse, anchor=west, xshift=1.0cm}}
\tikzset{my arrow/.style={-latex, thick}}

\begin{tikzpicture}
\node [my ellipse]                (Int Source)       at (0, 0) {Int Source};
\node [my ellipse]                (duplicate)        at (Int Source.east) {duplicate};
\node [my ellipse, yshift=+1.0cm] (High Pass Filter) at (duplicate.east) {High Pass Filter};
\node [my ellipse, yshift=-1.0cm] (Low Pass Filter)  at (duplicate.east) {Low Pass Filter};
\node [my ellipse, yshift=-1.0cm] (roundrobin)       at (High Pass Filter.east) {roundrobin(1,1)};
\node [my ellipse]                (IntPrinter)       at (roundrobin.east) {IntPrinter};

\draw [my arrow] (Int Source.east)       -- (duplicate.west);
\draw [my arrow] (duplicate.east)        -- (High Pass Filter.west);
\draw [my arrow] (duplicate.east)        -- (Low Pass Filter.west);
\draw [my arrow] (High Pass Filter.east) -- (roundrobin.west);
\draw [my arrow] (Low Pass Filter.east)  -- (roundrobin.west);
\draw [my arrow] (roundrobin.east)       -- (IntPrinter.west);
\end{tikzpicture}
\end{document}


and obtain what looks promising:

Well, the edges above are not quite what we wanted for the middle part of the diagran. So we need to adjust how we connect those nodes. Luckily we can access and edge of the node form any angle with the <node name>.<angle> specification. So, using:

\draw [my arrow] (duplicate.10)         -- (High Pass Filter.-175);
\draw [my arrow] (duplicate.-10)        -- (Low Pass Filter.175);
\draw [my arrow] (High Pass Filter.-10) -- (roundrobin.175);
\draw [my arrow] (Low Pass Filter.10)   -- (roundrobin.-175);


## 6 Dealing with the nested nodes:

Well that is actually easier than it might first appear with the use of the fit tikz library. We just need to define a a new virtual node that is fit around the existing nodes. Luckily we named all the nodes so this is quite easy. Using just

\node [draw=red, ultra thick,
fit=(duplicate) (High Pass Filter) (Low Pass Filter) (roundrobin)
] {};


we obtain a nice fitted rectangle around the nodes we specified:

Well this overlaps one of the arrows, so we just need to Make some extra space when using TikZ fit package by using a point that is left of the (duplicate) node. While we are at is we might as well tweak the right side of the red rectangle as well:

\node [draw=red, ultra thick,
fit={($(duplicate.west)-(0.4cm,0)$)
(High Pass Filter) (Low Pass Filter)
([xshift=0.4cm]roundrobin.east)}
] {};


Note that I have shown two different methods to adjust the points above. Once uses the syntax of the tikz calc pacakge, and the other applies an [xshift=] syntax.

So, this looks pretty good, now we just need to add the outer box:

\node [draw=red, ultra thick,
fit={($(duplicate.west)-(0.4cm,0)$)
(High Pass Filter) (Low Pass Filter)
([xshift=0.4cm]roundrobin.east)}
] {};
\node [draw=brown, ultra thick,
fit=(Int Source) (High Pass Filter) (Low Pass Filter) (IntPrinter)
] {};


Well, it looks like we need to adjust the fit nodes here as well:

\node [draw=red, ultra thick,
fit={($(duplicate.west)-(0.4cm,0)$)
(High Pass Filter)
(Low Pass Filter)
([xshift=0.4cm]roundrobin.east)}
] {};
\node [draw=brown, ultra thick,
fit={(Int Source)
([yshift=0.4cm]High Pass Filter.north)
([yshift=-0.4cm]Low Pass Filter.south)
(IntPrinter)}
] {};


## 7. Labeling the nested nodes:

Unfortunately, I forgot to place the labels of these nested nodes. So it appears that the above extensions of the will need to be extended a bit further north to make room for the node text. Best way to place those would be to use the north points of the use nested nodes.

## Code:

\documentclass[border=2pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{fit}
\usetikzlibrary{shapes}

\begin{document}

\tikzset{my ellipse/.style={
draw=blue,
ultra thick,
ellipse,
anchor=west,
xshift=1.0cm},
}
\tikzset{my arrow/.style={-latex, thick}}

\begin{tikzpicture}
\node [my ellipse]                (Int Source)       at (0, 0)                  {Int Source};
\node [my ellipse]                (duplicate)        at (Int Source.east)       {duplicate};
\node [my ellipse, yshift=+1.0cm] (High Pass Filter) at (duplicate.east)        {High Pass Filter};
\node [my ellipse, yshift=-1.0cm] (Low Pass Filter)  at (duplicate.east)        {Low Pass Filter};
\node [my ellipse, yshift=-1.0cm] (roundrobin)       at (High Pass Filter.east) {roundrobin(1,1)};
\node [my ellipse]                (IntPrinter)       at (roundrobin.east)       {IntPrinter};

\draw [my arrow] (Int Source.east)      -- (duplicate.west);
\draw [my arrow] (duplicate.10)         -- (High Pass Filter.-175);
\draw [my arrow] (duplicate.-10)        -- (Low Pass Filter.175);
\draw [my arrow] (High Pass Filter.-10) -- (roundrobin.175);
\draw [my arrow] (Low Pass Filter.10)   -- (roundrobin.-175);
\draw [my arrow] (roundrobin.east)      -- (IntPrinter.west);

\node [draw=red, ultra thick,
fit={($(duplicate.west)-(0.5cm,0)$)
([yshift=0.40cm]High Pass Filter.north)
(Low Pass Filter)
([xshift=0.4cm]roundrobin.east)}
] (Band Pass Filter) {};
\node [draw=brown, ultra thick,
fit={(Int Source)
([yshift=0.9cm]High Pass Filter.north)
([yshift=-0.4cm]Low Pass Filter.south)
(IntPrinter)}
] (Pipeline) {};

\node [anchor=north, font=\bfseries] at (Band Pass Filter.north) {Band Pass Filter};
\node [anchor=north, font=\bfseries] at (Pipeline.north) {Pipeline};

\end{tikzpicture}
\end{document}

-
Any feedback on the usefulness of these kind of tutorials would be welcome. –  Peter Grill Dec 7 '12 at 3:59
(+1) useful. Suggestion/feedback/notes: 1. nodes’ baseline aren’t at the same height (is that even a problem?); 2a. the filter nodes centered (they’re both left aligned to [xshift=+1cm]duplicate.east); 2b. the lower filter node having the same width as the other; 3. arrows going from the filter nodes mirroring the arrows going to them (length/angle), giving a more symmetric look; 4. fitted boxes behind the arrows; 5. the positioning library (which opens up to all kinds of possibilities): e.g. right=of <node name> and node distance=1cm. –  Qrrbrbirlbel Dec 7 '12 at 4:40

For clarity and maybe other users and as suggested by @percusse in a comment in the question, one good answer is to use the fit library as following:

\node[fit=(nodenames) (that) (I want to) (be covered)] {};

-