Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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}
share|improve this question
1  
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 at 11:32
    
@ChristianHupfer Done. Thanks! –  elaRosca Apr 26 at 12:23

3 Answers 3

up vote 11 down vote accepted

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.

enter image description here

\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}
share|improve this answer

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).

enter image description here

\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}
share|improve this answer

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}
    % Create your nodes first
    \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}
    % Create your nodes first
    \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}
share|improve this answer
    
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 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 at 12:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.