6

I have a problem with controlling the size of fit nodes in tikzpicture. I want the fit node to cover all the area but it does not seem to be working. I searched around but I have not found the solution yet. I would like to ask for your help. Thank you very much. Below is the tex of the figure. I also the image illustrating the wanted target.

\documentclass{article}
\usepackage{forest}
\usetikzlibrary{shapes,positioning}

\begin{document}
% Define the flowchart
\tikzstyle{startstop} = [draw, rounded rectangle, text centered, draw=black]
\tikzstyle{io} = [trapezium, trapezium left angle=70, trapezium right angle=110, text centered, draw=black]
\tikzstyle{process} = [rectangle,inner sep=-0.1ex, minimum height=1cm, text centered, text width=4cm, draw=black]
\tikzstyle{decision} = [diamond, aspect=2, inner sep=-1ex,  text centered, text width=4cm,  draw=black]
\tikzstyle{arrow} = [thick,->,>=stealth, rounded corners]
\begin{figure}[!htb]
\centering
\begin{tikzpicture}[node distance=1.4cm]
\node (start) [startstop] {Start};
\node (in1) [io, below = 0.5 of start, align= center] {$V$: an input sample vector \\ $\alpha$: a user-specified number};
\node (pro1) [process, below of=in1] {Do something};
\node (pro2) [process, below of=pro1] {Do something};
\node (pro3) [process, right of=pro2, xshift=4cm] {Do something};
\node (dec1) [decision, above of=pro3, yshift=0.4cm] {Check condition?};
\node (out1) [io, above of = dec1, yshift=0.4cm] {Output something};
\node (stop) [startstop, above = 0.5 of out1] {Stop};
\node (fit1) [dashed, rounded corners, fill=none, fit=(in1) (pro2), draw] {};
\node (fit2) [dashed, rounded corners, fill=none, fit=(pro3) (out1), draw] {};
\node[rotate=90, anchor=south] at (fit1.west) {The first step};
\node[rotate=90, anchor=south] at (fit2.west) {The second step};

\draw [arrow] (start) -- (in1);
\draw [arrow] (in1) -- (pro1);
\draw [arrow] (pro1) -- (pro2);
\draw [arrow] (pro2) -- (pro3);
\draw [arrow] (pro3) -- (dec1);
\draw (dec1.east) node[above right, xshift=0.4cm] {False}; \node[above left] at (dec1.north) {True};
\draw [arrow] (dec1.east) -- +(1,0) |- (pro3);
\draw [arrow] (dec1) -- (out1);
\draw [arrow] (out1) -- (stop);
\end{tikzpicture}
\end{figure}

\end{document}

enter image description here

1
  • The two solutions given by @Zarko and Schrödinger's cat work well. Thank you for your help! – Clark Jan 8 '20 at 7:27
6

enter image description here

Node with fit=<node name> actually consider width of the text in node with shapes trapezium and diamond and not their shapes extremes. This means, that we need to consider <node name>.bottom left corner and <node name>.top right corner at trapezium and <node name>.west and <node name>.east at diamond shapes.

\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{chains,
                fit,
                positioning,
                shapes}

\begin{document}
    \begin{tikzpicture}[
   node distance = 8mm and 12mm,
     start chain = A going below,
     start chain = B going above,
     base/.style = {draw, align=center, 
                    inner sep=2mm, on chain=A, join=by arr},
startstop/.style = {base, rounded rectangle},
       io/.style = {base, text width=42mm, trapezium, trapezium stretches body,
                    trapezium left angle=75, trapezium right angle=105},
  process/.style = {base, text width=44mm, minimum height=1cm},
 decision/.style = {base, text width=40mm, diamond, aspect=2, inner xsep=-4mm},
      arr/.style = {-stealth}
                        ]
\node   [startstop] {Start};                        % A-1
\node   [io] {$V$: an input sample vector \\ 
              $\alpha$: a user-specified number};
\node   [process] {Do something};
\node   [process] {Do something};                   % A-4
    \node (f1) [draw, rounded corners, dashed, 
                fit=(A-2.bottom left corner) (A-2.top right corner) (A-4),
                label={[rotate=90, anchor=south]left:The first step}] {};
%  
    \begin{scope}[base/.append style={on chain=B}]  % B-1
\node   [process, right=of A-4] {Do something};
\node   [decision]      {Check condition?};
\node   [io]            {Output something};
\node   [startstop]     {Stop};                     % B-4
    \end{scope}
%
\draw[arr]  (A-4) -- (B-1);
\draw[arr] (B-2.east) node (false) [above right] {False} -- + (1,0) |- (B-1);
\node[above left] at (B-2.north) {True};
%
    \node (f2) [draw, rounded corners, dashed, 
                fit=(B-1) (B-3.bottom left corner) (B-3.top right corner) (false),
                label={[rotate=90,anchor=south]left:The second step}] {};
    \end{tikzpicture}
\end{document}

Note: node names are determined by chain name: A-i for nodes in the left branch of the flowchart and B-i for nodes in the right branch.

2
  • Thanks for your kind answer Zarko, How can I make \node(f2) cover all this arrow (\draw[arr] (B-2.east) node[above right] {False} -- + (1,0) |- (B-1);) and the False node as my attached image? – Clark Jan 8 '20 at 5:18
  • 1
    @Clark, of course it can. I overlooked this.See edited answer. – Zarko Jan 8 '20 at 7:08
6

This answer focuses on the (IMHO really interesting) question why the fits are too tight. The key in understanding this behavior is in the lines

\def\tikz@lib@fit@scan@handle#1{%
  \iftikz@shapeborder%
    % Ok, fit all four external anchors, if they exist
    \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{west}}%
    \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{east}}%
    \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{north}}%
    \tikz@lib@fit@adjust{\pgfpointanchor{\tikz@shapeborder@name}{south}}%
  \else%
    \tikz@lib@fit@adjust{#1}%
  \fi%
  \tikz@lib@fit@scan%
}%

of tikzlibraryfit.code.tex. This tacitly assumes that anything that fits the the west, east, north and south anchors will fit the whole node. However, for the trapezium this is not the case, see p. 790 of pgfmanual v3.1.5

enter image description here

That means that for the trapezium shapes we need to fit other anchors. In the case at hand these are

\node (fit1) [dashed, rounded corners, fill=none, fit=(in1.top right corner)
  (in1.bottom left corner) (pro2), draw] {};
\node (fit2) [dashed, rounded corners, fill=none, fit=(pro3) (out1.top right corner)
  (out1.bottom left corner) (false), draw] {};

There are several other things changed (no more \tikzstyle, proper positioning etc.) but describing them in detail will just distract from the main point: using the above-mentioned anchors solves the problem.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{positioning,fit,shapes.misc,shapes.geometric}
\begin{document}
\begin{tikzpicture}[startstop/.style = {rounded rectangle},
       io/.style = {text width=42mm, trapezium, trapezium stretches body,
                    trapezium left angle=75, trapezium right angle=105},
  process/.style = {text width=44mm, minimum height=1cm},
 decision/.style = {text width=40mm, diamond, aspect=2, inner xsep=-4mm},
 lbl/.style={draw=none,inner sep=2pt},
      node distance=1cm and 1.6cm]
 \begin{scope}[nodes= {draw, align=center,inner sep=2mm}]
  \node (start) [startstop] {Start};
  \node (in1) [io, below = 0.5 of start, align= center] {$V$: an input sample vector \\ $\alpha$: a user-specified number};
  \node (pro1) [process, below=of in1] {Do something};
  \node (pro2) [process, below=of pro1] {Do something};
  \node (pro3) [process, right=of pro2] {Do something};
  \node (dec1) [decision, above=of pro3] {Check condition?};
  \node (out1) [io, above=of dec1] {Output something};
  \node (stop) [startstop, above=of out1] {Stop};
  \node (fit1) [dashed, rounded corners, fill=none, fit=(in1.top right corner)
  (in1.bottom left corner) (pro2), draw] {};
  \draw[-stealth] (dec1.east) -- +(1,0) node[above=0.5ex,lbl](false){False} |- (pro3);
  \node (fit2) [dashed, rounded corners, fill=none, fit=(pro3) (out1.top right corner)
  (out1.bottom left corner) (false), draw] {};
 \end{scope} 
 \node[rotate=90, anchor=south] at (fit1.west) {The first step};
 \node[rotate=90, anchor=south] at (fit2.west) {The second step};
 \begin{scope}[-stealth]
  \draw (start) -- (in1);
  \draw (in1) -- (pro1);
  \draw (pro1) -- (pro2);
  \draw (pro2) -- (pro3);
  \draw (pro3) -- (dec1);
  \draw (dec1) -- node[left=0.5ex,lbl]{True} (out1);
  \draw (out1) -- (stop);     
 \end{scope}  
\end{tikzpicture}
\end{document}

enter image description here

Of course one may not want to guess the anchors one has include. One way to avoid this is to work with local bounding boxes. In principle one could then drop fit completely but I keep it since the question is on fit.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{positioning,fit,shapes.misc,shapes.geometric}
\begin{document}
\begin{tikzpicture}[startstop/.style = {rounded rectangle},
       io/.style = {text width=42mm, trapezium, trapezium stretches body,
                    trapezium left angle=75, trapezium right angle=105},
  process/.style = {text width=44mm, minimum height=1cm},
  decision/.style = {text width=40mm, diamond, aspect=2, inner xsep=-4mm},
  lbl/.style={draw=none,inner sep=2pt},
      node distance=1cm and 1.6cm]
 \begin{scope}[nodes= {draw, align=center,inner sep=2mm}]
  \node (start) [startstop] {Start};
  \begin{scope}[local bounding box=F1]
   \node (in1) [io, below = 0.5 of start, align= center] {$V$: an input sample vector \\ $\alpha$: a user-specified number};
   \node (pro1) [process, below=of in1] {Do something};
   \node (pro2) [process, below=of pro1] {Do something};
  \end{scope}
  \begin{scope}[local bounding box=F2]
   \node (pro3) [process, right=of pro2] {Do something};
   \node (dec1) [decision, above=of pro3] {Check condition?};
   \node (out1) [io, above=of dec1] {Output something};
  \end{scope}
  \draw[-stealth] (dec1.east) -- +(1,0) node[above=0.5ex,lbl](false){False} |- (pro3);
  \node (stop) [startstop, above=of out1] {Stop};
  \node (fit1) [dashed, rounded corners, fill=none, fit=(F1), draw] {};
  \node (fit2) [dashed, rounded corners, fill=none, fit=(F2)(false), draw] {};
 \end{scope} 
 \node[rotate=90, anchor=south] at (fit1.west) {The first step};
 \node[rotate=90, anchor=south] at (fit2.west) {The second step};
 \begin{scope}[-stealth]
  \draw (start) -- (in1);
  \draw (in1) -- (pro1);
  \draw (pro1) -- (pro2);
  \draw (pro2) -- (pro3);
  \draw (pro3) -- (dec1);
  \draw (dec1) -- node[left,lbl]{True} (out1);
  \draw (out1) -- (stop);     
 \end{scope}  
\end{tikzpicture}
\end{document}

enter image description here

1
  • Thanks for your expalaination Schrödinger's cat, How can I make \node (fit2) cover all the arrow (\draw (dec1.east) -- +(1,0) node[above]{False} |- (pro3);) and the False node as my attached image? – Clark Jan 8 '20 at 5:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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