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 need to replicate this chart using LaTeX, I understand that TikZ should come in handy:

enter image description here

Can anyone please show me the best and easiest way to render the chart? Any ideas, tips, nudges in the right direction on how to do that are highly welcome.

share|improve this question
    
There are plenty of examples on the TikZ website, like this one: texample.net/tikz/examples/work-breakdown-structure –  wwjoze Mar 22 '13 at 10:46
2  
I'd use the chains library; you might have some clues in Draw a multi-chain structure. –  Claudio Fiandrino Mar 22 '13 at 11:17

3 Answers 3

up vote 22 down vote accepted

This is also doable just with the calc library and nothing else.

Layers deployment

At first we should locate the various livelli (italian plural of livello): nodes are just fine. Let's then define their aspect:

\tikzset{layer/.style={draw,
   rectangle, 
   fill=green!85!blue!60,
   minimum width=2cm
   }
}

Since they have very similar labels (just the layer number changes), I think the best choice here is to locate them by means a foreach loop; but... how to locate nodes sequentially? This is a possible way:

\foreach \i in {1,...,5}{
 \node[layer] (layer-1-\i) at (0,0+\i*1cm) {Livello \i};
}

Indeed, in such a way each time \i increments, also the y coordinate of the layer is incremented as well as the "counter" of its name and label. Each node is placed at a given vertical distance thanks to the syntax 0+\i*1cm: change 1cm to increase or reduce the space between the layers.

For the other stack it is just needed to change x coordinate and the name (layer-2-\i rather than layer-1-\i):

\foreach \i in {1,...,5}{
 \node[layer] (layer-2-\i) at (5.5,0+\i*1cm) {Livello \i};
}

enter image description here

Now the large block on the bottom. Well, to have it of the exact size we can use a function able to compute it:

\makeatletter
\def\CalcDistance(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{west}}{\pgfpointanchor{#2}{east}}
\pgfmathsetmacro{\myheight}{veclen(\pgf@x,\pgf@y)}
\global\expandafter\edef\csname #3\endcsname{\myheight}
}
\makeatother

This, applied to a couple of our layers gives the \distance:

\CalcDistance(layer-1-1,layer-2-1){distance}

The large block now should be located:

\node[layer, minimum width=\distance, yshift=-1cm] (low-module) at ($(layer-1-1.east)!0.5!(layer-2-1.west)$) {Mezzo fisico};

Its position can be computed to be placed exactly in the middle of the lowest level layers: this result should be shifted down to avoid covering layer livello 1.

enter image description here

Arrows and labels deplyoment

Once finished with the layers, the arrows. We can define a style for the type:

\tikzset{connective arrow/.style={
     stealth-stealth
   }
}

and now we're ready to add them to the picture.

Without considering for the moment the large module, for the others there's a similar behaviour: the arrow starts from the north anchor of the lower layer up to the south anchor of the next layer. So basically we need to be able to reference two counters: this is again a job for the foreach.

\foreach \i[evaluate=\i as \nexti using int(\i+1)] in {1,...,4}{
\draw[connective arrow] (layer-1-\i.north)--(layer-1-\nexti.south)
 node [midway,anchor=east, font=\footnotesize,left=0.15cm]{interfaccia livello \i/\nexti};
}

The evaluation allows indeed not only to identify the layers via their name, but it is also helpful for the label interfaccia livello \i/\nexti, put as a node at the middle (midway) left (anchor=east,left=0.15cm) of the arrow. The font size is a bit reduced to make the picture look better: the font key is of course used.

Same thing for the other column (just change the column name and the position of the arrow labels from left to right):

\foreach \i[evaluate=\i as \nexti using int(\i+1)] in {1,...,4}{
\draw[connective arrow] (layer-2-\i.north)--(layer-2-\nexti.south)
 node [midway,anchor=west, font=\footnotesize,right=0.15cm]{interfaccia livello \i/\nexti};
}

enter image description here

Let's now take into account the protocollo livello connection. It's basically similar to what did before, without having to evaluate anything:

\foreach \i in {1,...,5}{
\draw[connective arrow,draw=violet!50!blue] (layer-2-\i.west)--(layer-1-\i.east)
 node [midway, font=\footnotesize,above=-0.05cm]{protocollo livello \i};
}

The above=-0.05cm is used to have the label a bit more near the arrow.

enter image description here

Final addings

The picture is almost done: just a couple of things should be added. The first one is the connections between the two layers 1 and the large module; by computing the intersection via this is very simple:

\draw[connective arrow] (layer-1-1.south)--(low-module.north-|layer-1-1.south);
\draw[connective arrow] (layer-2-1.south)--(low-module.north-|layer-2-1.south);

enter image description here

Since they are just two arrows I won't use a foreach for this purpose. Even for the host label, I would use simple nodes:

\node[above=0.15cm,font=\Large,red] at (layer-1-5.north) {Host 1};
\node[above=0.15cm,font=\Large,red] at (layer-2-5.north) {Host 2};

Here the font size has been made bigger always via the font key.

enter image description here

And now our picture is really finished therefore here it is the whole code:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}

\tikzset{layer/.style={draw,
   rectangle, 
   fill=green!85!blue!60,
   minimum width=2cm
   },
   connective arrow/.style={
     stealth-stealth
   }
}

\makeatletter
\def\CalcDistance(#1,#2)#3{%
\pgfpointdiff{\pgfpointanchor{#1}{west}}{\pgfpointanchor{#2}{east}}
\pgfmathsetmacro{\myheight}{veclen(\pgf@x,\pgf@y)}
\global\expandafter\edef\csname #3\endcsname{\myheight}
}
\makeatother

\begin{document}
\begin{tikzpicture}
% Drawing the modules
% Column 1
\foreach \i in {1,...,5}{
 \node[layer] (layer-1-\i) at (0,0+\i*1cm) {Livello \i};
}
% Column 2
\foreach \i in {1,...,5}{
 \node[layer] (layer-2-\i) at (5.5,0+\i*1cm) {Livello \i};
}
% Bottom module
\CalcDistance(layer-1-1,layer-2-1){distance}
\node[layer, minimum width=\distance, yshift=-1cm] (low-module) at ($(layer-1-1.east)!0.5!(layer-2-1.west)$) {Mezzo fisico};

% Arrows
% Column 1
\foreach \i[evaluate=\i as \nexti using int(\i+1)] in {1,...,4}{
\draw[connective arrow] (layer-1-\i.north)--(layer-1-\nexti.south)
 node [midway,anchor=east, font=\footnotesize,left=0.15cm]{interfaccia livello \i/\nexti};
}
% Column 2
\foreach \i[evaluate=\i as \nexti using int(\i+1)] in {1,...,4}{
\draw[connective arrow] (layer-2-\i.north)--(layer-2-\nexti.south)
 node [midway,anchor=west, font=\footnotesize,right=0.15cm]{interfaccia livello \i/\nexti};
}
% Between columns
\foreach \i in {1,...,5}{
\draw[connective arrow,draw=violet!50!blue] (layer-2-\i.west)--(layer-1-\i.east)
 node [midway, font=\footnotesize,above=-0.05cm]{protocollo livello \i};
}

% LAST THINGS
% arrows towards bottom module
\draw[connective arrow] (layer-1-1.south)--(low-module.north-|layer-1-1.south);
\draw[connective arrow] (layer-2-1.south)--(low-module.north-|layer-2-1.south);

% host labels
\node[above=0.15cm,font=\Large,red] at (layer-1-5.north) {Host 1};
\node[above=0.15cm,font=\Large,red] at (layer-2-5.north) {Host 2};

\end{tikzpicture}
\end{document}

Considerations

The picture is perfectly scalable: it means that using

\begin{tikzpicture}[scale=0.5,transform shape]

its dimensions are correctly set to be half of the previous one. This is because, even if some fixed units have been used (1cm for the block vertical distance, above=-0.05cm for protocol labels and above=0.15cm for host labels), their positioning, actually, is always defined in terms of other nodes or in the midway of a path.

To introduce the possibility to easy customize the vertical block distance, one might think about introducing a new key (in the preamble):

\pgfkeys{/tikz/.cd,
  vertical distance/.initial=1cm,
  vertical distance/.get=\vertdist,
  vertical distance/.store in=\vertdist,
}

Then, \vertdist should be applied to:

% Drawing the modules
% Column 1
\foreach \i in {1,...,5}{
 \node[layer] (layer-1-\i) at (0,0+\i*\vertdist) {Livello \i};
}
% Column 2
\foreach \i in {1,...,5}{
 \node[layer] (layer-2-\i) at (5.5,0+\i*\vertdist) {Livello \i};
}
% Bottom module
\CalcDistance(layer-1-1,layer-2-1){distance}
\node[layer, minimum width=\distance, yshift=-\vertdist] (low-module) at ($(layer-1-1.east)!0.5!(layer-2-1.west)$) {Mezzo fisico};

In such a way, using:

\begin{tikzpicture}[vertical distance=2cm]

the block distance will be doubled with respect to the current setting.

share|improve this answer
    
Amazing answer, detailed and complete. Vote up –  N3buchadnezzar Jun 21 '13 at 22:58

I had a similar one and adapted it to your needs.

With an matrix of nodes it's easy to place all boxes and just need some draw commands for links between them.

\documentclass[border=1mm,tikz]{standalone}

\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}
\usepackage{tikz}
\usetikzlibrary{matrix, arrows,fit}

\begin{document}
\begin{tikzpicture}[font=\sffamily\footnotesize,%
        >=stealth',
        livello/.style={draw=green!70,fill=green!15,%
                thick,minimum height=6mm,%
                text width=25mm,align=center}]

    \matrix (A) [matrix of nodes, nodes=livello,
             row sep=6mm,column sep=3cm]
    {
   |(A-5-1)| Livello 5 & |(A-5-2)| Livello 5 \\                              
   |(A-4-1)| Livello 4 & |(A-4-2)| Livello 4 \\                              
   |(A-3-1)| Livello 3 & |(A-3-2)| Livello 3 \\                              
   |(A-2-1)| Livello 2 & |(A-2-2)| Livello 2 \\                              
   |(A-1-1)| Livello 1 & |(A-1-2)| Livello 1 \\                              
   |(A-0-1)| Livello 0 & |(A-0-2)| Livello 0 \\                              
    };

    \foreach \i/\j in {1/2,2/3,3/4,4/5}
   {
        \draw [<->] (A-\i-1)--(A-\j-1) node [left,midway] {interfaccia livello \i/\j};
        \draw [<->] (A-\i-2)--(A-\j-2) node [right,midway] {interfaccia livello \i/\j};
    }
    \draw [<->] (A-0-1)--(A-1-1);
    \draw [<->] (A-0-2)--(A-1-2);
    \foreach \i in {1,...,5}
        \draw [<->] (A-\i-1) -- (A-\i-2) node [above, midway]{protocol livello \i}; 

  \node[fit={(A-0-1) (A-0-2)},inner sep=0pt,draw=green!70,fill=green!15,%
                thick,label={center:mezzo fisico}] {};
 \node [red,above] at (A-5-1.north) {Host 1}; 
 \node [red,above] at (A-5-2.north) {Host 2}; 

\end{tikzpicture}%
\end{document} 

enter image description here

share|improve this answer

Simple replication with the usage of tikz::chain library.

Current issues:

  • Change colors.
  • Prettify source code. Maybe Livello nodes can be done via \foreach.

Code:

\documentclass[tikz]{standalone}

\usepackage{tikz}
  \usetikzlibrary{chains,fit}

\begin{document}
    \begin{tikzpicture}[livello/.style={draw=green,fill=green!15},
            host/.style={draw=none,fill=none,font=\Large},
            arrowlabel/.style={draw=none,fill=none,font=\scriptsize}]
        \begin{scope}[start chain=1 going above,start chain=2 going right,node distance=2em and 9em]
            \node[livello,on chain=1] (L1) {Livello 1};
            \node[livello,on chain=1] (L2) {Livello 2};
            \node[livello,on chain=1] (L3) {Livello 3};
            \node[livello,on chain=1] (L4) {Livello 4};
            \node[livello,on chain=1] (L5) {Livello 5};
            \node[host,on chain=1] (Host1) {Host 1};
            \chainin (L1);
            \node[livello,on chain=2] (R1) {Livello 1};
            \node[livello,continue chain=going above,on chain=2] (R2) {Livello 2};
            \node[livello,on chain=2] (R3) {Livello 3};
            \node[livello,on chain=2] (R4) {Livello 4};
            \node[livello,on chain=2] (R5) {Livello 5};
            \node[host,on chain=2] (Host2) {Host 2};
        \end{scope}

        \foreach \value/\nextvalue in {1/2,2/3,3/4,4/5} {
          \draw[<->] (L\value.north) -- (L\nextvalue.south) node[arrowlabel,midway,left] {interfaccia livello \value/\nextvalue};
          \draw[<->] (R\value.north) -- (R\nextvalue.south) node[arrowlabel,midway,right] {interfaccia livello \value/\nextvalue};
        }

        \foreach \value in {1,...,5}
          \draw[<->] (L\value.east) -- (R\value.west) node[arrowlabel,midway,above] (middle\value) {protocollo livello \value};

        \node[livello,fit=(L1) (R1),below=3em of middle1,label=center:Mezzo fisico] (root) {};
        \draw[<->] (L1.south) -- (L1.south|-root.north);
        \draw[<->] (R1.south) -- (R1.south|-root.north);
    \end{tikzpicture}
\end{document}

Result:

diagram

share|improve this answer

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.