# Tikz fit variable number of nodes

I would like to draw a rectangle or ellipse over some nodes I am drawing with tikz.

I know how to do that if the number of nodes is fixed: I just enumerate them.

I was wondering if there is a way to do that if I have a variable number of nodes?

Currently I use something like this:

     \node[draw,dotted,fit=(V1) (V2)] {};


But I have multiple nodes that I would like to fit in, and their number is given by a variable. Is there a work around this? Ideally I would like something like this, that enumerates trough all nodes

\node[draw,dotted,fit=(V1) .. (V\numvis)] {};


Because of the layout of my nodes I can actually just use:

\node[draw,dotted,fit=(V1) (V\numvis)] {};


But I am interested in the more general way, so that I have something in case I change layouts.

Thanks!

Here is the complete working code:

\documentclass[11pt, twoside]{article}
\usepackage{tikz}
\usetikzlibrary{fit,matrix,chains,positioning,decorations.pathreplacing,arrows}

\begin{document}
\begin{figure}[h]
\centering
\def\layersep{2cm} % Gap between visible & hidden units
\def\numvis{8} % Number if visible units
\def\numhid{5} % Number of hidden units
\def\numhidsnd{5}
\def\numhidthrd{4}
\begin{tikzpicture}[
node distance=\layersep,
line/.style={shorten >=2pt,shorten <=2pt,>=stealth},
downarrow/.style={<-,shorten >=2pt,shorten <=2pt,>=stealth, thick,},
uparrow/.style={->,shorten >=2pt,shorten <=2pt,>=stealth, thick, color=red},
doublearrow/.style={<->,shorten >=2pt,shorten <=2pt,>=stealth, thick},
surround/.style={draw=blue, thick, dotted, rounded corners},
]
\tikzstyle{neuron}=[circle,fill=black!25,minimum size=21pt,inner sep=0pt];
\tikzstyle{visible neuron}=[neuron];
\tikzstyle{hidden neuron}=[neuron];
\tikzstyle{annot}=[text width=10em];

% Iterate over visible units
\foreach \name / \y in {1,...,\numvis}
\node[visible neuron] (V\name) at (\y,0) {};

% Iterate over hidden units
\foreach \name / \y in {1,...,\numhid}
% Calculate the appropriate offset for the hidden unit based on the
% number of visible units.
\pgfmathparse{\y + (\numvis - \numhid) * 0.5}
\node[hidden neuron] (H\name) at (\pgfmathresult, \layersep) {};

\foreach \name / \y in {1,...,\numhidsnd}
% Calculate the appropriate offset for the hidden unit based on the
% number of visible units.
\pgfmathparse{\y + (\numhid - \numhidsnd) * 0.5}
\node[hidden neuron] (H2\name) at (\pgfmathresult + 1.5, 2 * \layersep) {};

\foreach \name / \y in {1,...,\numhidthrd}
% Calculate the appropriate offset for the hidden unit based on the
% number of visible units.
\pgfmathparse{\y + (\numhidsnd - \numhidthrd) * 0.5}
\node[hidden neuron] (H3\name) at (\pgfmathresult + 1.5, 3 * \layersep) {};

\node[surround, dotted,fit=(V1)  (V\numvis)] (allvis) {};
\node[surround, fit=(H1)  (H\numhid)] (allhid) {};
\node[surround, fit=(H21)  (H2\numhidsnd)] (allhid2) {};
\node[surround, fit=(H31)  (H3\numhidthrd)] (allhid3) {};

\draw[uparrow] (allvis) -- (allhid);
\draw[uparrow] (allhid) -- (allhid2);
\draw[downarrow] (allvis) -- (allhid);
\draw[downarrow] (allhid) -- (allhid2);

\draw[doublearrow] (allhid2) -- (allhid3);

\node[annot,left of=V1, node distance=1.5cm] (hl) {Visible layer};
\node[annot,  above of=hl] (a) {Hidden layer};
\node[annot, above of=a] (b){Hidden layer};
\node[annot, above of=b] (c) {Hidden layer};

\end{tikzpicture}
\caption{Generative versus recognition weights in a DBN.}
\label{fig:rbm}
\end{figure}

\end{document}

-
Please help us to help you and add a minimal working example (MWE) that illustrates your problem. It will be much easier for us to reproduce your situation and find out what the issue is when we see compilable code, starting with \documentclass{...} and ending with \end{document}. –  Christian Hupfer Apr 26 '14 at 11:32
@ChristianHupfer Done. Thanks! –  elaRosca Apr 26 '14 at 12:23

With the foreach syntax, you can easely discribe the nodes you want to fit:

\foreach \i in {1,...,5,9,\start,...,\end}


for example. \start and \end and some other are dynamicaly calculated.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{fit}

\begin{document}
\begin{tikzpicture}

\foreach \i in {1,...,25} {%
\pgfmathsetmacro{\RandX}{(rand*5 + 1) - 2.5} ;
\pgfmathsetmacro{\RandY}{(rand*5 + 1) - 2.5} ;
\node (V\i) at (\RandX,\RandY) {\i} ;
}

\xdef\Loop{}
\foreach \n in {1,2,4} {\xdef\Loop{\Loop(V\n)} }

\node[draw=red,fit=\Loop] {};

\end{tikzpicture}
\end{document}

-

You may apply the following auto fit option to each special node. Its argument is the name of a collection of special nodes to fit (and the name of the resulting node).

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{fit}

\makeatletter
% see http://tex.stackexchange.com/a/37713
\def\@nodeundefined#1{\@ifundefined{pgf@sh@ns@#1}}
%
\tikzset{auto fit/.style={append after command={
\pgfextra{
\begin{pgfinterruptpath}
\@nodeundefined{#1}{
\node[fit=(\tikzlastnode),inner sep=0,line width=0](#1){};
}{
\node[fit=(#1)(\tikzlastnode),inner sep=0,line width=0](#1){};
}
\end{pgfinterruptpath}
}}}}
\makeatother

\begin{document}
\begin{tikzpicture}
\node[font=\small,auto fit=a] (V1) at ({random(0,10)},{random(0,10)}) {1} ;
\node[font=\small,auto fit=b] (V2) at ({random(0,10)},{random(0,10)}) {2} ;
\node[font=\small,auto fit=a] (V3) at ({random(0,10)},{random(0,10)}) {3} ;
\node[font=\small,auto fit=b] (V4) at ({random(0,10)},{random(0,10)}) {4} ;
\node[font=\small,auto fit=a] (V5) at ({random(0,10)},{random(0,10)}) {5} ;

\node[draw=blue,fit=(a)]{};
\node[draw=red,fit=(b)]{};
\end{tikzpicture}
\end{document}

-

If I understand your question correctly then you want to draw a rectangle around nodes. All you have to do it to draw the nodes first, and then draw a rectangle using the corners of the picture's bounding box.

Also you can group your nodes into scopes, give the scopes name and reference them by their names.

\documentclass[a4paper]{article}

\usepackage{tikz}

\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}
\node (n1) at (0, 0) {n1};
\node (n2) at (5, 3) {n2};
% ...
\node (nm) at (-2, -2) {nm};

% After drawing the nodes, you can enclose
% them into a rectangle using the bounding
% box of the already drawn nodes
\draw (current bounding box.north west) rectangle
(current bounding box.south east);
\end{tikzpicture}

\begin{tikzpicture}
\node (n1) at (0, 0) {n1};
\node (n2) at (5, 3) {n2};
% ...
\node (nm) at (-2, -2) {nm};

% After drawing the nodes, you can enclose
% them into a rectangle using the bounding
% box of the already drawn nodes
%
% Note: this rectangle will leave 0.5cm space
% between the nodes and the sides of the rectangle
% (the calc tikz library was loaded for this)
\draw[color=red] ($(current bounding box.north west) + (-0.5, 0.5)$)
rectangle ($(current bounding box.south east) + (0.5, -0.5)$);
\end{tikzpicture}

\begin{tikzpicture}
% Create your nodes inside scopes and give names to the scopes
\begin{scope}[local bounding box=nodegroup1]
\node (n1) at (0, 0) {n1};
\node (n2) at (1, 1) {n2};
% ...
\node (nk) at (1, -1) {nk};
\end{scope}

\begin{scope}[local bounding box=nodegroup2]
\node (m1) at (3, 0) {m1};
\node (m2) at (4, 1) {m2};
% ...
\node (ml) at (4, -1) {ml};
\end{scope}

% Now you can reference the bounding boxes of the scopes with their names
\draw[color=blue] ($(nodegroup1.north west) + (-0.5, 0.5)$) rectangle
($(nodegroup1.south east) + (0.5, -0.5)$);

\draw[color=green] ($(nodegroup2.north west) + (-0.5, 0.5)$) rectangle
($(nodegroup2.south east) + (0.5, -0.5)$);

\end{tikzpicture}

\end{document}


Your MWE with using scopes for grouping:

\documentclass[11pt, twoside]{article}
\usepackage{tikz}
\usetikzlibrary{fit, matrix, chains, positioning, decorations.pathreplacing, arrows, calc}

\begin{document}
\begin{figure}[h]
\centering
\def\layersep{2cm} % Gap between visible & hidden units
\def\numvis{8} % Number if visible units
\def\numhid{5} % Number of hidden units
\def\numhidsnd{5}
\def\numhidthrd{4}
\begin{tikzpicture}[
node distance=\layersep,
line/.style={shorten >=2pt,shorten <=2pt,>=stealth},
downarrow/.style={<-,shorten >=2pt,shorten <=2pt,>=stealth, thick,},
uparrow/.style={->,shorten >=2pt,shorten <=2pt,>=stealth, thick, color=red},
doublearrow/.style={<->,shorten >=2pt,shorten <=2pt,>=stealth, thick},
%surround/.style={draw=blue, thick, dotted, rounded corners},
surround/.style={color=blue, thick, dotted, rounded corners}
]
\tikzstyle{neuron}=[circle,fill=black!25,minimum size=21pt,inner sep=0pt];
\tikzstyle{visible neuron}=[neuron];
\tikzstyle{hidden neuron}=[neuron];
\tikzstyle{annot}=[text width=10em];

% Iterate over visible units
\begin{scope}[local bounding box=group1]
\foreach \name / \y in {1,...,\numvis}
\node[visible neuron] (V\name) at (\y,0) {};
\end{scope}

% Iterate over hidden units
\begin{scope}[local bounding box=group2]
\foreach \name / \y in {1,...,\numhid}
% Calculate the appropriate offset for the hidden unit based on the
% number of visible units.
\pgfmathparse{\y + (\numvis - \numhid) * 0.5}
\node[hidden neuron] (H\name) at (\pgfmathresult, \layersep) {};
\end{scope}

\begin{scope}[local bounding box=group3]
\foreach \name / \y in {1,...,\numhidsnd}
% Calculate the appropriate offset for the hidden unit based on the
% number of visible units.
\pgfmathparse{\y + (\numhid - \numhidsnd) * 0.5}
\node[hidden neuron] (H2\name) at (\pgfmathresult + 1.5, 2 * \layersep) {};
\end{scope}

\begin{scope}[local bounding box=group4]
\foreach \name / \y in {1,...,\numhidthrd}
% Calculate the appropriate offset for the hidden unit based on the
% number of visible units.
\pgfmathparse{\y + (\numhidsnd - \numhidthrd) * 0.5}
\node[hidden neuron] (H3\name) at (\pgfmathresult + 1.5, 3 * \layersep) {};
\end{scope}

\draw[surround] ($(group1.north west) + (-2.5pt, 2.5pt)$) rectangle
($(group1.south east) + (2.5pt, -2.5pt)$);
\draw[surround] ($(group2.north west) + (-2.5pt, 2.5pt)$) rectangle
($(group2.south east) + (2.5pt, -2.5pt)$);
\draw[surround] ($(group3.north west) + (-2.5pt, 2.5pt)$) rectangle
($(group3.south east) + (2.5pt, -2.5pt)$);
\draw[surround] ($(group4.north west) + (-2.5pt, 2.5pt)$) rectangle
($(group4.south east) + (2.5pt, -2.5pt)$);

\draw[latex-latex] ($(group1.north) + (0, 3.5pt)$) --
($(group2.south) + (0, -3.5pt)$);
\draw[latex-latex] ($(group2.north) + (0, 3.5pt)$) --
($(group3.south) + (0, -3.5pt)$);
\draw[latex-latex] ($(group3.north) + (0, 3.5pt)$) --
($(group4.south) + (0, -3.5pt)$);

\node[annot, left of=V1, node distance=1.5cm] (hl) {Visible layer};
\node[annot, above of=hl] (a) {Hidden layer};
\node[annot, above of=a] (b){Hidden layer};
\node[annot, above of=b] (c) {Hidden layer};
\end{tikzpicture}
\caption{Generative versus recognition weights in a DBN.}
\label{fig:rbm}
\end{figure}

\end{document}
`
-
But this would work if I want to select all of the nodes. What if I want to select only some of them? –  elaRosca Apr 26 '14 at 12:07
@elaRosca You can use scopes to enclose your nodes. Give names to the scopes and then you can reference them by their names. I edited the answer and added an example how to do this. –  szantaii Apr 26 '14 at 12:23