使用 LaTeX 复制此图表

使用 LaTeX 复制此图表

我需要使用 LaTeX 复制此图表,我知道 TikZ 应该会派上用场:

在此处输入图片描述

有人能告诉我呈现图表的最佳和最简单的方法吗?任何关于如何做到这一点的想法、提示和正确方向的提示都非常受欢迎。

答案1

这也是仅使用calc图书馆就可以做到的,不需要其他任何东西。

分层部署

首先,我们应该找到各种livelli(意大利语复数livello):节点就好了。然后让我们定义它们的方面:

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

由于它们的标签非常相似(只是层数不同),我认为最好的选择是通过循环来定位它们foreach;但是……如何按顺序定位节点?这是一种可能的方法:

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

事实上,这样每次时间\i增加,层的坐标及其名称和标签的“计数器”都会增加。每个节点都放置在给定的垂直距离处,这要归功于语法0+\i*1cm:更改1cm以增加或减少层之间的空间。

对于其他堆栈,只需更改X坐标和名称(layer-2-\i而不是layer-1-\i):

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

在此处输入图片描述

现在来看看底部的大块。好吧,为了得到它的精确尺寸,我们可以使用一个能够计算它的函数:

\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

将其应用到我们的几个层上可得到\distance

\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};

可以计算出它的位置正好位于最低层中间:应该将此结果向下移动以避免覆盖第livello1 层。

在此处输入图片描述

箭头和标签部署

完成图层和箭头后,我们可以为类型定义样式:

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

现在我们准备将它们添加到图片中。

暂时不考虑大模块,其他模块的行为类似:箭头从north下层的锚点开始,一直到south下一层锚点。所以基本上我们需要能够引用两个计数器:这又是 的工作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};
}

评估不仅允许通过名称识别图层,而且标签也很有帮助interfaccia livello \i/\nexti,标签作为节点放在箭头中间 ( midway) 左侧 ( anchor=east,left=0.15cm)。字体大小略有减小,以使图片看起来更好:font当然使用键。

对另一列也进行同样的操作(只需从左到右更改列名称和箭头标签的位置):

\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};
}

在此处输入图片描述

现在让我们考虑一下protocollo livello连接。它基本上与之前所做的类似,无需评估任何内容:

\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};
}

用于above=-0.05cm使标签稍微靠近箭头。

在此处输入图片描述

最后添加

图片几乎完成了:只需添加几件事。第一个是两个层 1 和大模块之间的连接;通过这个计算交集非常简单:

\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);

在此处输入图片描述

由于它们只是两个箭头,因此我不会为此使用foreach。即使对于host标签,我也会使用简单的节点:

\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};

此处,字体大小始终通过该键变大font

在此处输入图片描述

现在我们的图像已经真正完成了,因此这里是完整的代码:

\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}

注意事项

图片完全可扩展:这意味着使用

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

它的尺寸被正确地设置为前一个的一半。这是因为,即使使用了一些固定单位(1cm用于块垂直距离、above=-0.05cm协议标签和above=0.15cm主机标签),它们的位置实际上总是根据其他节点或路径的中间来定义的。

为了引入轻松定制垂直块距离的可能性,人们可能会考虑引入一个新密钥(在序言中):

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

然后,\vertdist应适用于:

% 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};

以这种方式,使用:

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

阻挡距离将相对于当前设置增加一倍。

答案2

我有一个类似的,并根据您的需要进行了调整。

通过它matrix of nodes可以轻松放置所有盒子,并且只需要一些draw命令来链接它们。

\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} 

在此处输入图片描述

答案3

使用tikz::chain库进行简单复制。

当前的问题:

  • 改变颜色。
  • 美化源代码。也许利韦洛节点可以通过 完成\foreach

代码:

\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}

结果:

图表

相关内容