我需要使用 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};
可以计算出它的位置正好位于最低层中间:应该将此结果向下移动以避免覆盖第livello
1 层。
箭头和标签部署
完成图层和箭头后,我们可以为类型定义样式:
\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}
结果: