3

This is second attempt to reproduce the diagram below. enter image description here

It was recommended that I use fit library, I tried it out and I got to the point below:

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

\nodeconv {\rotatebox{90}{Train Data}};

\nodeconv, above=0.9cm of conv1 {\rotatebox{90}{Generator}}; \nodeconv, below=0.9cm of conv1 {\rotatebox{90}{Ref. Data }};

% \nodeplate,right=4.9cm of conv1{}; % yshift to align the bottom of that blocks with the previous taller block. \nodeblock,right=3.cm of conv1,yshift=0.001cm{\rotatebox{90}{1}};

\draw [-triangle 60,link2] ([xshift=0.1cm,yshift=0.2cm]conv1.east) -- ([xshift=0.0cm,yshift=0.2cm]resblock1.west);

\nodeblock,right=0.1cm of resblock1{\rotatebox{90}{1}};

% \nodeblock,above=0.1cm of resblock1{\rotatebox{90}{2}}; % \nodeblock,above=0.1cm of resblock2{\rotatebox{90}{3}}; % \nodeblock,right=0.2cm of resblock1{\rotatebox{90}{(X4)}}; % \nodeblock,above=0.1cm of x1{\rotatebox{90}{Dense Layer}}; % \nodeblock,above=0.1cm of x2{\rotatebox{90}{(X2)}}; \nodeplate,right=0.2cm of resblock2{\rotatebox{90}{BatchNorm}}; \nodeblock2,right=0.2cm of plate2{\rotatebox{90}{ResBlock4}}; \nodeblock2,right=0.1cm of resblock4{\rotatebox{90}{ResBlock6}};

\nodeplate2,right=0.2cm of resblock6{\rotatebox{90}{\small BatchNorm}};;

\nodeblock3,right=0.3cm of plate3{\rotatebox{90}{ \small ResBlock5}};

\nodeconv2,right=0.2cm of resblock5{\rotatebox{90}{Conv}}; \nodedraw=red,very thick, fit=(resblock1) (resblock1) (plate2) (resblock4) (resblock4) (plate3) (resblock5) (last) {}; % \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}

This was inspired by the solution here Producing stacked 3D blocks using TikZ and the recommendation from the solution here Flow diagam and 3D diagrams tikz .

The output I have now is as below:

enter image description here

I want to :

  1. add the arrows properly and format the fit the rectangle appropriately
  2. add the text accordingly.

Thanks

  • Why do you use the path picture option and not just fill the shapes? You can try right=0.1cm of resblock1.south east, anchor=south west to align the blocks at the bottom. – Jasper Habicht Apr 06 '23 at 06:20
  • As for the fit problem, you can always either use anchors (if they exist) or xshift/yshift as options to the coordinates you want to fit (like ([yshift=1cm]resblock1) for example), to correctly fit the node. Note that you need to place the argument to the fit option inside curly braces ({}) if you want to use square brackets ([]) inside. – Jasper Habicht Apr 06 '23 at 06:25
  • @JasperHabicht I appreciate the feedback. I will work on the recommendations accordingly. – koolaids Apr 06 '23 at 06:35
  • 1
    The fit library only takes the main compass anchors (north, east, south and west) in consideration when you just give it a node name. The shape's definition doesn't change any of these anchors from the original rectangle which is why the 3d-ness of that shape is basically invisible for fit. There's room for improvement in that shape's definition. As a workaround you could have those cuboids create coordinates automatically on-the-fly and use them in fit to avoid having to use [yshift=1cm] like @JasperHabicht suggested. – Qrrbrbirlbel Apr 06 '23 at 08:42
  • @Qrrbrbirlbel True, yshift should probably only be used together with coordinates in the context of fit. I just suggested it as another option which I though might be easier for the OP then to redefine the shape. – Jasper Habicht Apr 06 '23 at 09:29
  • Why did you tag it circuitikz? I do not see where I can help here... – Rmano Apr 06 '23 at 12:11
  • 1
    @Rmano that was my mistake. I have removed the tag accordingly. Thank you for the observation. – koolaids Apr 06 '23 at 14:53
  • @koolaids thanks! – Rmano Apr 06 '23 at 16:51

1 Answers1

1
  1. I've condensed your styles down to a few:

    • a common block with the most commen settings (shape and its offset, draw and text = white),
    • plate that is the same as block but the fill color is lightblue instead of darkblue,
    • conv that are the thinner (→ smaller offset) orange blocks.

    Then, they are the three sizes: size 1, size 2and size 3.

  2. Instead of placing all those nodes inside the fit box manually, I'm using the chains library with the custom bottom right placement rule which makes the nodes bottom-aligned.

    This rule is set by using start chain = going bottom right and then placing each node on chain.

  3. We can now use two nested \foreach loops to place the nodes, the outer loop determines its size by its own counter \CNT and the inner loop goes through each size group and actually places the \nodes with the appropriate \STYLE.

  4. While the chains library implicitly gives aliases to the nodes, we still need to give them manually explicit names so that we can actually use the effects of the every parallelepiped node style which places a coordinate at the (real) upper right corner of your boxes. (It'd be better to improve the shape and add real anchors but that'll do for now.)

  5. In the value for the fit key we not only use the bare name of the first node gr1-1 but also these coordinates gr1-1-North East and gr3-2-North East of which we know that they encompass everything.

  6. With outer sep set to zero we can now use the four sides of the rectangle to add text, arrows and a coordinate box-ne for later.

  7. The tree boxes on the left gets added.

  8. All edges get drawn.

Code

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

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • Awesome! Now I have a lot to learn from this. – koolaids Apr 06 '23 at 18:23
  • @koolaids No problems. It's probably not the perfect solution to what you're trying to achieve but maybe it gets you farther on the way. Don't forget that there's also the decoration.markings library that can place arrow tips along paths. It provides more functionality but or many instances my arrow pic is much easier to handle, in my opinion. – Qrrbrbirlbel Apr 06 '23 at 18:47