3

Here is a flowchart drawn using tikz. This is lot of code. The positions of some objects are computed by trial and error. How do I simplify it. Also how to make arrows connecting block 4 with the squiggly line straight?

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric, arrows}
\usetikzlibrary{decorations.pathreplacing,decorations.markings,snakes}
\tikzset
{ 
process/.style={rectangle, minimum width=2cm, minimum height=1cm, align=center, text width=2cm, draw},
connector/.style={circle, minimum width=1cm, minimum height=0.5cm, align=center, text width=1cm, draw},
arrow/.style={thick, ->, >=stealth},
database/.style={
      cylinder,
      shape border rotate=90,
      aspect=0.25,
      draw
    }
}  
\tikzset{snake it/.style={decorate, decoration=snake}}
\begin{document}
\begin{tikzpicture}
\node (p0){Layers in system xyz};
\node (a) [process, below of=p0, text width=6cm] {Block 1};
\node (b) [process, below of=a, yshift=-1cm, text width=6cm] {Block 2};
\node (c) [process, below of=b, yshift=-1cm, text width=6cm] {Block 3};
\node (d) [process, below of=c, yshift=-1cm, text width=6cm] {Block 4};
\node (e) [process, below of=d, yshift=-3cm, text width=6cm] {Block 5};
\node (f) [process, right of=e, xshift=7cm, text width=6cm] {Block 6};

\path (a.south) -- (a.south east) coordinate[pos=0.5] (a1);
\path (a.south) -- (a.south west) coordinate[pos=0.5] (a2);

\path (b.north) -- (b.north east) coordinate[pos=0.5] (b1);
\path (b.north) -- (b.north west) coordinate[pos=0.5] (b2);
\path (b.south) -- (b.south east) coordinate[pos=0.5] (b3);
\path (b.south) -- (b.south west) coordinate[pos=0.5] (b4);

\path (c.north) -- (c.north east) coordinate[pos=0.5] (c1);
\path (c.north) -- (c.north west) coordinate[pos=0.5] (c2);
\path (c.south) -- (c.south east) coordinate[pos=0.5] (c3);
\path (c.south) -- (c.south west) coordinate[pos=0.5] (c4);

\path (d.north) -- (d.north east) coordinate[pos=0.5] (d1);
\path (d.north) -- (d.north west) coordinate[pos=0.5] (d2);
\path (d.south) -- (d.south east) coordinate[pos=0.5] (d3);
\path (d.south) -- (d.south west) coordinate[pos=0.5] (d4);

\path [draw,snake it]  (-3,-9) -- node[right, xshift=4 cm] { n/w}(3,-9);

\draw[latex-] (a1) -- (b1);
\draw[latex-] (b2) -- (a2);
\draw[latex-] (b3) -- (c1);
\draw[latex-] (c2) -- (b4);
\draw[latex-] (c3) -- (d1);
\draw[latex-] (d2) -- (c4);
\draw[latex-] (1.5,-8.5) --  node[right] {hi} (d3);
\draw[latex-] (d4) -- (-1.5,-8.5);
\draw[latex-] (1.5,-10.5) -- (1.5,-9.5);
\draw[latex-] (-1.5,-9.5) -- (-1.5,-10.5);
\draw [dashed] (e.east) -- (f.west);

\node[database] (db1) at (-2,-13) {DB1};
\node[database] (db2) at (2,-13) {DB2};
\node[database] (db3) at (6,-13) {DB3};
\node[database] (db4) at (10,-13) {DB4};
\end{tikzpicture}
\end{document}

Output

2
  • How close to the squiggly line do you want the arrows to get? Commented Aug 18, 2015 at 1:19
  • I've updated the code to reflect the distances.
    – arunmoezhi
    Commented Aug 18, 2015 at 1:25

2 Answers 2

4

This is a response to the original question before the diagram was retroactively expanded by the OP!

This uses the chains library to create the header, snake and, using a single loop, the 4 blocks. The arrows between the main blocks are drawn as part of the same loop. Finally, the arrows to and from the snake are drawn following the same pattern.

\documentclass[tikz, border=20pt]{standalone}
\usetikzlibrary{chains,arrows.meta,decorations.pathmorphing}
\begin{document}
\begin{tikzpicture}
  [start chain=main going below, every on chain/.append style={align=center, text width=60mm, minimum height=10mm}, >={LaTeX[]}]
  \node [on chain] {Layers in system xyz};
  \foreach \i [remember=\i as \iprior] in {1,...,4}
  {
    \node (block \i) [on chain, draw] {Block \i};
    \ifnum\i>1
      \draw [->] (block \iprior.south) +(-15mm,0) coordinate (b\i) -- (block \i.north -| b\i);
      \draw [<-] (block \iprior.south) +(15mm,0) coordinate (k\i) -- (block \i.north -| k\i);
    \fi
  }
  \node (squiggle) [on chain] {};
  \draw [decorate, decoration={snake}] (squiggle.west) -- (squiggle.east);
  \draw [->] (block 4.south -| b4) -- (squiggle -| b4);
  \draw [<-] (block 4.south -| k4) -- (squiggle -| k4);
\end{tikzpicture}
\end{document}

condensed patterning with chains and loops

This could be further shortened, but I think it would thereby be significantly less intelligible.

EDIT

This is a response to the revised question after the diagram was extensively expanded by the OP.

Again, this uses the chains library together with some loops and a few conditionals. It also uses the quotes library to make adding nodes by the arrows easier. It is designed to be extensible so that labels can easily be added to any arrow in the diagram.

\documentclass[tikz, border=20pt]{standalone}
\usetikzlibrary{chains,arrows.meta,decorations.pathmorphing,quotes}
\begin{document}
\begin{tikzpicture}
  [start chain=main going below, every on chain/.append style={align=center, text width=60mm, minimum height=10mm}, >={LaTeX[]}, every edge quotes/.append style={midway, auto, font=\small}, every label/.append style={font=\small}]
  \node [on chain] {Layers in system xyz};
  \foreach \i [remember=\i as \iprior] in {1,...,6}
  {
    \ifnum\i=5
      \node (block s) [on chain, label=right:n/w] {};
      \draw [decorate, decoration={snake}] (block s.west) -- (block s.east);
    \else
      \ifnum\i>5
        \node (block \iprior) [on chain, draw] {Block \iprior};
      \else
        \node (block \i) [on chain, draw] {Block \i};
      \fi
    \fi
  }
  \foreach \i/\j/\k [remember=\i as \iprior (initially 1)] in {2//,3//,4//,s//hi,5//}
  {
    \draw (block \iprior.south) +(-15mm,0) coordinate (b\i) edge ["\j", ->] (block \i.north -| b\i);
    \draw (block \iprior.south) +(15mm,0) coordinate (k\i) edge ["\k", <-] (block \i.north -| k\i);
  }
  \node (block 6) [on chain=going right, draw, join=by {dashed}] {Block 6};
\end{tikzpicture}
\end{document}

more chains

The addition of the beer barrels at the bottom is left as an exercise for the reader.

EDIT EDIT

Addition of beer barrels:

beer barrels

Complete Code

\documentclass[tikz, border=20pt]{standalone}
\usetikzlibrary{chains,arrows.meta,decorations.pathmorphing,quotes,shapes.geometric}
\begin{document}
\begin{tikzpicture}
  [start chain=main going below, every on chain/.append style={align=center, text width=60mm, minimum height=10mm}, >={LaTeX[]}, every edge quotes/.append style={midway, auto, font=\small}, every label/.append style={font=\small}, database/.style={cylinder, shape border rotate=90, aspect=0.25, draw}]
  \node [on chain] {Layers in system xyz};
  \foreach \i [remember=\i as \iprior] in {1,...,6}
  {
    \ifnum\i=5
      \node (block s) [on chain, label=right:n/w] {};
      \draw [decorate, decoration={snake}] (block s.west) -- (block s.east);
    \else
      \ifnum\i>5
        \node (block \iprior) [on chain, draw] {Block \iprior};
      \else
        \node (block \i) [on chain, draw] {Block \i};
      \fi
    \fi
  }
  \foreach \i/\j/\k [remember=\i as \iprior (initially 1)] in {2//,3//,4//,s//hi,5//}
  {
    \draw (block \iprior.south) +(-15mm,0) coordinate (b\i) edge ["\j", ->] (block \i.north -| b\i);
    \draw (block \iprior.south) +(15mm,0) coordinate (k\i) edge ["\k", <-] (block \i.north -| k\i);
  }
  \node (block 6) [on chain=going right, draw, join=by {dashed}] {Block 6};
  \path [every node/.style=database] (b5 |- block 5.south) +(0,-10mm) node (db1) {DB1} (k5 |- db1) node {DB2} (block 6.south |- db1) +(-15mm,0) node (db3) {DB3} +(15mm,0) node {DB4};
\end{tikzpicture}
\end{document}

Explanation

Starting with the options passed to tikzpicture:

  [start chain=main going below, 

This creates a chain named main which is heading downwards. So each node added will be added below the one before.

every on chain/.append style={align=center, text width=60mm, minimum height=10mm},

Every node which uses the style on chain i.e. every node added to a chain of any sort will have the style attributes given i.e. minimum height of 1cm, text width of 6cm, text aligned to centre.

>={LaTeX[]}, 

Every arrow tip will, by default, be of this kind (using the new syntax from the arrows.meta library which replaces arrows).

every edge quotes/.append style={midway, auto, font=\small},

The quotes library lets you say things like ... edge ["great label"] ... as a shorthand for ... edge node {great label} .... every edge quotes sets a style to be applied to all nodes specified in this way.

every label/.append style={font=\small}, 

All label nodes will use small text.

database/.style={cylinder, shape border rotate=90, aspect=0.25, draw}]

Style from your code.

  \node [on chain] {Layers in system xyz};

First node on the chain called main.

  \foreach \i [remember=\i as \iprior] in {1,...,6}

Starts a loop with one variable \i which will take the value 1, then 2, then ... 6. After the first loop, the previous value of \i will be available as \iprior. So, when \i is 2, \iprior will be 1.

  {% everything here to be repeated for each \i
    \ifnum\i=5

If \i is 5, we want to create the special snake thing rather than a block. We call this block s. We add it, as usual to the chain.

      \node (block s) [on chain, label=right:n/w] {};
      \draw [decorate, decoration={snake}] (block s.west) -- (block s.east);
    \else

If we aren't dealing with the special case, then we distinguish 2 cases: blocks before the snake and blocks after it.

      \ifnum\i>5% blocks after the snake i.e. block 5
        \node (block \iprior) [on chain, draw] {Block \iprior};

In this case, we want the previous value of \i, \iprior because our snake stepped the value of \i even though we didn't create a regular block.

      \else% blocks before the snake i.e. blocks 1-4
        \node (block \i) [on chain, draw] {Block \i};
      \fi
    \fi
  }

Completes drawing of blocks 1-5 and the snake.

  \foreach \i/\j/\k [remember=\i as \iprior (initially 1)] in {2//,3//,4//,s//hi,5//}

Three variables here. Again, the previous value of \i is saved as \iprior. In the first iteration of the loop, \iprior will be equal to 1. We start \i from 2 because we don't want arrows going into and out of the top of block 1.

The syntax a/b/c means set \i to a, \j to b and \k to c. i here is the number of the block to draw arrows into and out of and \j and \k are any labels those arrows should take.

  {% repeat this set for each triplet of values \i, \j and \k
    \draw (block \iprior.south) +(-15mm,0) coordinate (b\i) edge ["\j", ->] (block \i.north -| b\i);
    \draw (block \iprior.south) +(15mm,0) coordinate (k\i) edge ["\k", <-] (block \i.north -| k\i);

This is where the quotes stuff is used. It sets \j and \k as labelling nodes for the arrows drawn. (a -| b) means the point which is on the same shelf as a (-) and above the same point on the ground as b (|) i.e. x coordinate from b and y coordinate from a.

  }

Complete the loop over the set of triplets.

  \node (block 6) [on chain=going right, draw, join=by {dashed}] {Block 6};

Add block 6 which means we want the chain to go in a different direction, so instead of on chain, we say on chain=going right. Here, we tell TikZ to join the block to the previous one using a dashed line. (Couldn't use this above because join doesn't get you 2 arrows - only 1.)

Finally, add the beer barrels at the bottom. This is using the |- syntax explained above.

  \path [every node/.style=database] (b5 |- block 5.south) +(0,-10mm) 

Start at the point with x coordinte from b5 (defined earlier) and y from block5.south and then come down 10mm.

node (db1) {DB1}

Make the first database, name it db1.

 (k5 |- db1) node {DB2}

Align the second database with k5 and the first database.

(block 6.south |- db1) +(-15mm,0) node (db3) {DB3}

We don't have b6 or k6 so we need to adjust left and right manually by moving 15mm left to place the third database...

+(15mm,0) node {DB4};

and 15mm right to place the fourth.

5
  • Thank you. And apologies for not mentioning that I edited the code.
    – arunmoezhi
    Commented Aug 18, 2015 at 1:03
  • The addition of the beer barrels at the bottom is left as an exercise for the reader. Good one :)
    – arunmoezhi
    Commented Aug 18, 2015 at 1:27
  • Your code is concise. But it requires lots of learnings for a beginner to follow.
    – arunmoezhi
    Commented Aug 18, 2015 at 1:29
  • 1
    @arunmoezhi Couldn't resist adding the beer, after all. You did indicate you wanted less code ;). There are really only 2 key ideas here: one is the use of the chains library which basically adds nodes to chains. At any given time, a chain is going in a particular direction e.g. below or right and saying \node [on chain]... adds the node onto the chain. It makes it easy to add lots of nodes quickly. The other is the use of loops with \foreach.... Basically \i, \j, \k are variables and they loop through the things in the in {...}. So you repeat code for each step. What else?
    – cfr
    Commented Aug 18, 2015 at 1:42
  • @arunmoezhi Please see edit. I've tried to break the final code down. Let me know if you have questions.
    – cfr
    Commented Aug 18, 2015 at 2:29
3

Here's another option, not as shorter as cfr's answer. The main idea here is to take advantage of the positioning and calc libaries to place the elements. More lopps could've been used, but I decided to sacrify brevity over clarity:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric, arrows,positioning,calc}
\usetikzlibrary{decorations.pathreplacing,decorations.markings,snakes}

\tikzset
{ 
process/.style={rectangle, minimum width=2cm, minimum height=1cm, align=center, text width=6cm, draw},
connector/.style={circle, minimum width=1cm, minimum height=0.5cm, align=center, text width=1cm, draw},
arr/.style={->, >=latex},
revarr/.style={<-, >=latex},
database/.style={
      cylinder,
      shape border rotate=90,
      aspect=0.25,
      draw
    },
}  
\tikzset{snake it/.style={decorate, decoration=snake}}

\begin{document}

\begin{tikzpicture}
\def\Shift{40pt}
\node (p0){Layers in system xyz};
\node (1) [process, below=of p0] {Block 1};
\node (2) [process, below=of 1] {Block 2};
\node (3) [process, below=of 2] {Block 3};
\node (4) [process, below=of 3] {Block 4};
\coordinate[below=1.3cm of 4] (5);
\node (6) [process, below=1.3cm of 5] {Block 5};
\node (7) [process, right=of 6] {Block 6};

\path[draw,snake it]  
  (3.south west|-5) -- (3.south east|-5) node[right] { n/w} ;

\foreach \Valor in {1,...,3}
{
  \draw[arr] 
    ([xshift=-\Shift]\Valor.south) -- ([xshift=-\Shift]\the\numexpr\Valor+1\relax.north);
  \draw[revarr] 
    ([xshift=\Shift]\Valor.south) -- ([xshift=\Shift]\the\numexpr\Valor+1\relax.north);
}

\draw[revarr,shorten >= 0.3cm] 
    ([xshift=-\Shift]4.south) -- ([xshift=-\Shift]5.north);
\draw[revarr,shorten <= 0.3cm] 
    ([xshift=-\Shift]5.south) -- ([xshift=-\Shift]6.north);
\draw[arr,shorten >= 0.3cm] 
    ([xshift=\Shift]4.south) -- ([xshift=\Shift]5.north);
\draw[arr,shorten <= 0.3cm] 
    ([xshift=\Shift]5.south) -- ([xshift=\Shift]6.north);
\draw[dashed]
  (6) -- (7);

\path
  node[database] 
    (db1) at ([yshift=-1cm] $(6.south west)!0.25!(6.south east) $ ) {DB1} 
  node[database] 
    (db2) at ([yshift=-1cm] $(6.south west)!0.75!(6.south east) $ ) {DB2}
  node[database] 
    (db3) at ([yshift=-1cm] $(7.south west)!0.25!(7.south east) $ ) {DB3}
  node[database] 
    (db4) at ([yshift=-1cm] $(7.south west)!0.75!(7.south east) $ ) {DB4};
\end{tikzpicture}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .