有人建议我使用fit
库,我尝试了一下,得到了以下结论:
\documentclass[tikz]{standalone}
%% Language and font encodings
\usepackage[english]{babel}
\usepackage[utf8x]{inputenc}
\usepackage[T1]{fontenc}
\usetikzlibrary {fit}
\usepackage{xcolor}
\definecolor{darkblue}{HTML}{1f4e79}
\definecolor{lightblue}{HTML}{00b0f0}
\definecolor{salmon}{HTML}{ff9c6b}
\usetikzlibrary{backgrounds,calc,shadings,shapes.arrows,arrows,shapes.symbols,shadows,positioning,decorations.markings,backgrounds,arrows.meta}
% Define parallelepiped shape:
\makeatletter
\pgfkeys{/pgf/.cd,
parallelepiped offset x/.initial=2mm,
parallelepiped offset y/.initial=2mm
}
\pgfdeclareshape{parallelepiped}
{
\inheritsavedanchors[from=rectangle] % this is nearly a rectangle
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north west}
\inheritanchor[from=rectangle]{north east}
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{mid}
\inheritanchor[from=rectangle]{mid west}
\inheritanchor[from=rectangle]{mid east}
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{base west}
\inheritanchor[from=rectangle]{base east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south west}
\inheritanchor[from=rectangle]{south east}
\backgroundpath{
% store lower right in xa/ya and upper right in xb/yb
\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
\pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/parallelepiped
offset x}}
\pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/parallelepiped
offset y}}
\def\ppd@offset{\pgfpoint{\pgfutil@tempdima}{\pgfutil@tempdimb}}
\pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
\pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
\pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
\pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
\pgfpathclose
\pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya}}{\ppd@offset}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\ppd@offset}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@yb}}{\ppd@offset}}
\pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
\pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\ppd@offset}}
}
}
\makeatother
\tikzset{
% Dark blue blocks
block/.style={
parallelepiped,fill=white, draw,
minimum width=0.2cm,
minimum height=3.2cm,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm,
path picture={
\draw[top color=darkblue,bottom color=darkblue]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
% many
block2/.style={
parallelepiped,fill=white, draw,
minimum width=0.3cm,
minimum height=2.7cm,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm,
path picture={
\draw[top color=darkblue,bottom color=darkblue]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
%last
block3/.style={
parallelepiped,fill=white, draw,
minimum width=0.3cm,
minimum height=1.7cm,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm,
path picture={
\draw[top color=darkblue,bottom color=darkblue]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
% Orange-ish blocks
conv/.style={
parallelepiped,fill=white, draw,
minimum width=0.8cm,
minimum height=1.0cm,
parallelepiped offset x=0.1cm,
parallelepiped offset y=0.1cm,
path picture={
\draw[top color=salmon,bottom color=salmon]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
% Orange-ish blocks
conv2/.style={
parallelepiped,fill=white, draw,
minimum width=0.4cm,
minimum height=1.0cm,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm,
path picture={
\draw[top color=salmon,bottom color=salmon]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
% Taller Light blue blocks:
plate/.style={
parallelepiped,fill=white, draw,
minimum width=0.09cm,
minimum height=3.1cm,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm,
path picture={
\draw[top color=lightblue,bottom color=lightblue]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
% style
% Taller Light blue blocks:
plate2/.style={
parallelepiped,fill=white, draw,
minimum width=0.1cm,
minimum height=2.5cm,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm,
path picture={
\draw[top color=lightblue,bottom color=lightblue]
(path picture bounding box.south west) rectangle
(path picture bounding box.north east);
},
text=white,
},
% Arrows between blocks:
link/.style={
color=white,
line width=1mm,
},
link2/.style={
color=lightblue,
line width=1mm,
},
}
\begin{document}
\begin{tikzpicture}
% The order of blocks matters since some are partially hidden behind subsequent blocks.
\node[conv](conv1) {\rotatebox{90}{Train Data}};
\node[conv, above=0.9cm of conv1 ](conv3)
{\rotatebox{90}{Generator}};
\node[conv, below=0.9cm of conv1 ](conv2)
{\rotatebox{90}{Ref. Data }};
% \node[plate,right=4.9cm of conv1](plate1){};
% yshift to align the bottom of that blocks with the previous taller block.
\node[block,right=3.cm of conv1,yshift=0.001cm](resblock1){\rotatebox{90}{1}};
\draw [-triangle 60,link2] ([xshift=0.1cm,yshift=0.2cm]conv1.east) -- ([xshift=0.0cm,yshift=0.2cm]resblock1.west);
\node[block,right=0.1cm of resblock1](resblock2){\rotatebox{90}{1}};
% \node[block,above=0.1cm of resblock1](resblock2){\rotatebox{90}{2}};
% \node[block,above=0.1cm of resblock2](resblock3){\rotatebox{90}{3}};
% \node[block,right=0.2cm of resblock1](x1){\rotatebox{90}{(X4)}};
% \node[block,above=0.1cm of x1](x2){\rotatebox{90}{Dense Layer}};
% \node[block,above=0.1cm of x2](x3){\rotatebox{90}{(X2)}};
\node[plate,right=0.2cm of resblock2](plate2){\rotatebox{90}{BatchNorm}};
\node[block2,right=0.2cm of plate2](resblock4){\rotatebox{90}{ResBlock4}};
\node[block2,right=0.1cm of resblock4](resblock6){\rotatebox{90}{ResBlock6}};
\node[plate2,right=0.2cm of resblock6](plate3){\rotatebox{90}{\small BatchNorm}};;
\node[block3,right=0.3cm of plate3](resblock5){\rotatebox{90}{ \small
ResBlock5}};
\node[conv2,right=0.2cm of resblock5](last){\rotatebox{90}{Conv}};
\node[draw=red,very thick, fit=(resblock1) (resblock1) (plate2) (resblock4) (resblock4) (plate3) (resblock5) (last) ](fitter) {};
% \draw [-,link] ([xshift=0.2cm,yshift=0.2cm]last.east) -- ([yshift=0.2cm]last.west);
% \node[below] at (fit.south) {box};
\node[above] at (fitter.south) {box};
\node[below] at (fitter.north) {box};
\draw [link] ([xshift=1.cm,yshift=0.2cm]last.east) -- ([xshift=1.5cm,yshift=0.2cm]last.east) ;
\draw [-triangle 60,link2] ([xshift=0.1cm,yshift=0.2cm]fitter.west) -- ([xshift=0.0cm,yshift=0.2cm]conv3.east);
\draw [-triangle 60,link2] ([xshift=0.0cm,yshift=0.0cm]conv3.south) -- ([xshift=0.0cm,yshift=0.0cm]conv1.north);
\draw [-triangle 60,link2] ([xshift=0.0cm,yshift=0.0cm]conv2.north) -- ([xshift=0.0cm,yshift=0.0cm]conv1.south);
\end{tikzpicture}
\end{document}
这是受到此处解决方案的启发使用 TikZ 制作堆叠的 3D 块以及此处解决方案的建议流程图和 3D 图表 tikz。
我现在得到的输出如下:
我想要 :
- 正确添加箭头并适当格式化以适合矩形
- 添加相应的文本。
谢谢
答案1
我将您的风格浓缩为以下几种:
- 具有
block
最常见设置的通用设置(形状及其偏移,draw
和text = white
), plate
和 block 一样,但是fill
颜色lightblue
不是darkblue
,conv
它们是更薄的(→偏移量较小)橙色块。
那么,它们有三种尺寸:
size 1
、size 2
和size 3
。- 具有
我没有手动将所有节点放置在
fit
框内,而是使用chains
具有自定义bottom right
放置规则的库,使节点底部对齐。此规则是通过使用
start chain = going bottom right
然后放置每个节点来设置的on chain
。我们现在可以使用两个嵌套
\foreach
循环来放置节点,外循环通过其自己的计数器确定其大小\CNT
,内循环遍历每个大小组并\node
使用适当的位置实际放置 s\STYLE
。虽然
chains
库隐式地为节点提供了别名,但我们仍然需要手动为它们提供明确的名称,以便我们能够实际使用样式的效果,every parallelepiped node
该样式将坐标放置在框的(真实)右上角。(最好改进形状并添加真正的锚点,但现在就这样了。)在键的值中,
fit
我们不仅使用第一个节点的裸名称gr1-1
,还使用这些坐标gr1-1-North East
,并且gr3-2-North East
我们知道它们包含所有内容。将
outer sep
其设置为零后,我们现在可以使用矩形的四边来添加文本、箭头和坐标box-ne
以供以后使用。左侧的树框已添加。
所有边均被绘制。
代码
\documentclass[tikz]{standalone}
\usepackage[english]{babel}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\definecolor{darkblue}{HTML}{1f4e79}
\definecolor{lightblue}{HTML}{00b0f0}
\definecolor{salmon}{HTML}{ff9c6b}
\definecolor{buff}{RGB}{218, 160, 109}
\usetikzlibrary{backgrounds, chains, fit, positioning, arrows.meta, quotes}
% Define parallelepiped shape:
\pgfset{
parallelepiped offset x/.initial=2mm,
parallelepiped offset y/.initial=2mm}
\makeatletter
\pgfdeclareshape{parallelepiped}{%
\inheritsavedanchors[from=rectangle] % this is nearly a rectangle
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north west}
\inheritanchor[from=rectangle]{north east}
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{mid}
\inheritanchor[from=rectangle]{mid west}
\inheritanchor[from=rectangle]{mid east}
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{base west}
\inheritanchor[from=rectangle]{base east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south west}
\inheritanchor[from=rectangle]{south east}
\backgroundpath{%
% store lower right in xa/ya and upper right in xb/yb
\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
\pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/parallelepiped offset x}}%
\pgfmathsetlength\pgfutil@tempdimb{\pgfkeysvalueof{/pgf/parallelepiped offset y}}%
\def\ppd@offset{\pgfpoint{\pgfutil@tempdima}{\pgfutil@tempdimb}}%
\pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
\pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}%
\pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}%
\pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}%
\pgfpathclose
\pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}}%
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya}}{\ppd@offset}}%
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\ppd@offset}}%
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@yb}}{\ppd@offset}}%
\pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}%
\pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}%
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\ppd@offset}}%
}
}
\makeatother
\tikzset{
block/.style={
shape=parallelepiped,
fill=darkblue, draw, text=white,
parallelepiped offset x=0.5cm,
parallelepiped offset y=0.5cm},
size 1/.style={minimum width=0.2cm, minimum height=3.2cm},
size 2/.style={minimum width=0.3cm, minimum height=2.7cm},
size 3/.style={minimum width=0.3cm, minimum height=1.7cm},
% Orange-ish blocks
conv/.style={block, minimum width=0.8cm, minimum height=1.0cm,
fill=salmon, parallelepiped offset x=0.1cm, parallelepiped offset y=0.1cm},
% Taller Light blue blocks:
plate/.style={block, fill=lightblue},
}
\tikzset{% https://tex.stackexchange.com/a/674354/16595
pics/arrow/.style={/tikz/sloped, /tikz/allow upside down,
code=\pgfarrowdraw{#1}}, pics/arrow/.default=>,
every parallelepiped node/.style={
label/.expanded={[shape=coordinate,name=\noexpand\tikzlastnode-North East,
xshift={\pgfkeysvalueof{/pgf/parallelepiped offset x}},
yshift={\pgfkeysvalueof{/pgf/parallelepiped offset y}}]north east:}},
bottom right/.style={right=#1.south east, anchor=south west}}
\begin{document}
\begin{tikzpicture}[
> = {Triangle[angle'=45, scale=.5]},
|-/.style={to path=|-(\tikztotarget)\tikztonodes}
]
\newcommand*\rot[1]{\rotatebox{90}{#1}}
\begin{scope}[start chain=going bottom right, node distance=2mm]
\foreach[count=\CNT] \GROUP in {
{block/1, block/1, plate/BatchNorm},
{block/ResBlock4, block/ResBlock6, plate/BatchNorm},
{block/ResBlock5, conv/Conv}}
\foreach[count=\CCNT] \STYLE/\TEXT in \GROUP
\node[on chain, size \CNT/.try, \STYLE] (gr\CNT-\CCNT) {\rot{\TEXT}};
\end{scope}
\tikzset{line width=1mm}
\node[
fit=(gr1-1)(gr1-1-North East)(gr3-2-North East),
rounded corners=+5mm, draw,
inner sep=+8mm, outer sep=+0pt] (box) {};
\path[pos=.6] (box.north east) -- node[below, buff] {Some text, some text}
pic {arrow}
coordinate[pos=.2] (box-ne) (box.north west);
\path[at end, every pic/.append style={xshift=-5mm}]
(box.north west) -- pic{arrow} (box.south west)
(box.south east) -- pic{arrow} (box.north east);
\tikzset{node distance=.9cm and 2cm}
\node[conv, left =of box ] (trainData) {\rot{Train Data}};
\node[conv, above=of trainData] (generator) {\rot{Generator}};
\node[conv, below=of trainData] (refData) {\rot{Ref. Data}};
\path[->] (generator) edge (trainData)
(refData) edge (trainData)
[nodes=buff]
(box-ne) edge[|-, "Some text"' near end] (generator)
(trainData) edge[buff!50!black, shorten >=2mm, shorten <=2mm,
"Text", "Text"'] (box)
;
\end{tikzpicture}
\end{document}