8

I want to create the following picture with tikz

enter image description here

I got an MWE working but I have the following problems

  • I want the two boxes to span the current \linewidth
  • I want the "internal" nodes to be positioned relative to the boxes

Is there a possibility to achieve this?


MWE

\documentclass{standalone}
%
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{fit}
\usetikzlibrary{positioning}
% 
\begin{document}
% 
\pgfdeclarelayer{bg}    % declare background layer
\pgfsetlayers{bg,main}  % set the order of the layers (main is the standard layer)
%
\tikzset{
My Node Style/.style={
    rectangle
,rounded corners
,fill=gray
,minimum width=6em
,minimum height=5ex
}
}
% 
\tikzset{
My RectLabel Style/.style={
    draw=black
,fill=white
}
}
% 
\tikzset{
My Bg Style/.style={
    inner ysep=5pt
,inner ysep=20pt
,draw=black
,thick
,fill=lightgray
}
}
% 
\begin{tikzpicture}
\node (lib11) [My Node Style] at (0,0)            {Library 1-1};
\node (lib12) [My Node Style, right=1em of lib11] {Library 1-2};
\node (lib13) [My Node Style, right=1em of lib12] {Library 1-3};
\node (lib14) [My Node Style, right=1em of lib13] {Library 1-4};
%
\node (lib21) [My Node Style,above=15ex of lib11]  {Library 2-1};
\node (lib22) [My Node Style, right=1em of lib21] {Library 2-2};
\node (lib23) [My Node Style, right=1em of lib22] {Library 2-3};
\node (lib24) [My Node Style, right=1em of lib23] {Library 2-4};
\node (lib25) [My Node Style, right=1em of lib24] {Library 2-5};
%
\begin{pgfonlayer}{bg}    % select the background layer
    \node[fit={(lib11) (lib14)}, My Bg Style] (rect1) {};
    \node[My RectLabel Style] (rect1Label) at ($(rect1.north west)!0.5!(rect1.north east)$) {Layer 1};
\end{pgfonlayer}
%
\begin{pgfonlayer}{bg}    % select the background layer
    \node[fit={(lib21) (lib25)}, My Bg Style] (rect2) {};
    \node[My RectLabel Style] (rect2Label) at ($(rect2.north west)!0.5!(rect2.north east)$) {Layer 2};
\end{pgfonlayer}
%
\draw[->] (rect1Label.north) -- (rect2.south);
\end{tikzpicture}
% 
\end{document}
  • please, provide more information: (i) are inner boxes uniformly spread inside outer boxes? (ii) is width of inner boxes fixed (in case of longer text it should be broken in more lines)? – Zarko Aug 2 '18 at 23:06
  • What value should \linewidth have? Since you are using standalone that is a bit arbitrary. – marmot Aug 2 '18 at 23:07
  • The inner boxes should be uniformely spread inside the outer boxes. The width of the inner boxes should be determined by the amount of boxes and the linewidth. Line breaks are allowed. I used standalonefor the sake of the MWE. \linewidthis the usual width inside an article-based documentclass. – raedma Aug 2 '18 at 23:11
  • your addition to question is actually new question ... ask it as such! your problem before edit is solved by both answer. please accept one of them. – Zarko Aug 3 '18 at 11:27
5

Why not use tcolorbox? A tcbraster will do some work for us.

\documentclass{article}
\usepackage{lipsum}
\usepackage[most]{tcolorbox}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}

\tcbset{
    myraster/.style={
        raster columns=#1, 
        raster equal height, 
        size=small, 
        rounded corners, 
        frame hidden, 
        colback=gray,
        halign=center,
    },
    mybox/.style={
        colframe=black,
        sharp corners,
        coltitle=black,
        fontupper=\small,
        enhanced,
        attach boxed title to top center={yshift*=-\tcboxedtitleheight/2},
        boxed title style={
            colback=white,
            colframe=black,
            sharp corners,
            remember as={title #1},
        },
        title={#1},
        remember as={#1},
    }
}

\begin{document}
\lipsum[1]
\begin{tcboxeditemize}%
[%inner boxes properties
    myraster=5
]{%outer box properties
    mybox={Layer 2}
}
\tcbitem Library 2-1
\tcbitem Library 2-2
\tcbitem Library 2-3
\tcbitem Library 2-4
\tcbitem Library 2-5
\end{tcboxeditemize}
\vspace*{.5cm}
\begin{tcboxeditemize}%
[%inner boxes properties
    myraster=3
]{%outer box properties
    mybox={Layer 1}
}
\tcbitem Library 1-1
\tcbitem Library 1-2
\tcbitem Library 1-3
\end{tcboxeditemize}

\tikz[remember picture, overlay] \draw[<-] (Layer 2)--(title Layer 1);
\end{document}

enter image description here

Update:

When raster use more than one line, you can center last line contents with raster halign=center option.

Add it to myraster/.style in previous code and will get:

enter image description here

  • Thanks, I'll go with this solution as seems to offer the highest modularity. Just a quick question, in case I use myraster=3 in the Layer 2 box, it nicely breaks the 2 items at the end on a new line. Any chance i can get these 2 items centered instead of directly below the upper nodes and one missing on the right? And while we are at it, is it possible to make a colorbox or any kind of frame in the background around both layer boxes? – raedma Aug 3 '18 at 9:33
  • Based on Zarko's recommendation, I created a new question: tex.stackexchange.com/q/444448/44634 – raedma Aug 3 '18 at 11:35
  • @krtek look at updated answer for centering last line in raster. – Ignasi Aug 3 '18 at 12:01
8

You can make the boxes span the line width by using minimum width. The perhaps simplest possibility to uniformly distribute these boxes is using pos along a path that runs from left to right over the whole page. If the boxes have different widths, this won't work, but for your example it does. EDIT: Simplified the code, big thanks to Peter Grill!

\documentclass{article}
\usepackage[margin=1in]{geometry}
%
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{fit}
\usetikzlibrary{positioning}
% 
\begin{document}
%\setlength{\linewidth}{16cm}
% 
\pgfdeclarelayer{bg}    % declare background layer
\pgfsetlayers{bg,main}  % set the order of the layers (main is the standard layer)
%
\tikzset{
My Node Style/.style={
    rectangle
,rounded corners
,fill=gray
,minimum width=6em
,minimum height=5ex
}
}
% 
\tikzset{
My RectLabel Style/.style={
    draw=black
,fill=white
}
}
% 
\tikzset{
My Bg Style/.style={
    inner ysep=5pt,outer xsep=0pt,
,inner ysep=20pt
,draw=black
,thick
,fill=lightgray,minimum
    width=\linewidth-2*\pgflinewidth
}
}
% 
\begin{tikzpicture}
\path (2cm,0) -- (\linewidth-2cm,0)\foreach \X in {1,...,4}
{node (lib1\X) [My Node Style,pos=(\X-1)/3]             {Library 1-\X}};
\path (2cm,20ex) -- (\linewidth-2cm,20ex)\foreach \X in {1,...,5}
{node (lib2\X) [My Node Style,pos=(\X-1)/4]             {Library 2-\X}};
\begin{pgfonlayer}{bg}    % select the background layer
    \node[fit={(lib11) (lib14)}, My Bg Style] (rect1) {};
    \node[My RectLabel Style] (rect1Label) at ($(rect1.north west)!0.5!(rect1.north east)$) {Layer 1};
\end{pgfonlayer}
%
\begin{pgfonlayer}{bg}    % select the background layer
    \node[fit={(lib21) (lib25)}, My Bg Style] (rect2) {};
    \node[My RectLabel Style] (rect2Label) at ($(rect2.north west)!0.5!(rect2.north east)$) {Layer 2};
\end{pgfonlayer}
%
\draw[->] (rect1Label.north) -- (rect2.south);
\end{tikzpicture}
% 
\end{document}

enter image description here

  • 1
    You could move the \linewidth style into My Bg Style to simplify the code. – Peter Grill Aug 2 '18 at 23:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.