# Layered diagram with empty spaces

I am trying to achieve something like the following:

+---------------------+ +---------------+
|          A          | |       B       |
+---------------------+ +---------------+
+---------+
########1######## |    C    | #####2#####
+---------+
+---+ +---------+ +---------+ +---+ +---+
| D | |    E    | |    F    | | G | | H |
+---+ +---------+ +---------+ +---+ +---+
+---+
##3## | I | ###########4########### ##5##
+---+
+---------+ +---------------------+ +---+
|    J    | |          K          | | L |
+---------+ +---------------------+ +---+


Here, the hashtags are supposed to represent chunks of empty space. I have looked at this answer, but that solution does not quite fit my needs.

What I would like to do in order to specify my diagram, is design it row-by-row, left-to-right; sequentially listing all the blocks/empty spaces I want to draw.

In order to get the overlap right, I'd like to specify for each block/empty space, which blocks from the previous row it shares vertical space with. How do I do that? Or better yet, how do I get the desired final result?

It would be nice if adding a row that demands sharing vertical space of a narrow block would cause the block to be stretched. Take e.g. the example above; If C by itself would be narrow, having it share vertical space with A and B causes it to be come slightly wider. Similarly, since #4 shares some of E's vertical space, E has to become wider to accommodate I and part of #4. And finally, since H, #5 and L share the same vertical space, they should be equally wide.

Update (2013-12-11):
I have made an attempt to follow the suggestion pointing me towards TikZ matrices. Therefor I had to look up how to do column-spanning. Here's a MWE using that technique:

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{positioning,calc,matrix,fit}

\makeatletter
\newdimen\multi@col@width
\newdimen\multi@col@margin
\newcount\multi@col@count
\multi@col@width=0pt

\tikzset{
multicol/.code={%
\global\multi@col@count=#1\relax
\global\let\orig@pgfmatrixendcode=\pgfmatrixendcode
\global\let\orig@pgfmatrixemptycode=\pgfmatrixemptycode
\def\pgfmatrixendcode##1{\orig@pgfmatrixendcode%
##1%
\pgfutil@tempdima=\pgf@picmaxx
\global\multi@col@margin=\pgf@picminx
\divide\pgfutil@tempdima by #1\relax
\global\multi@col@width=\pgfutil@tempdima
\pgf@picmaxx=.5\multi@col@width
\pgf@picminx=-.5\multi@col@width
\global\pgf@picmaxx=\pgf@picmaxx
\global\pgf@picminx=\pgf@picminx
\setbox\pgf@matrix@cell=\hbox\bgroup
\hfil\hskip-1.5\multi@col@margin
\hfil\hskip-.5\multi@col@width
\box\pgf@matrix@cell
\egroup
}%
\aftergroup\multi@temp
}
\gdef\pgfmatrixemptycode{%
\orig@pgfmatrixemptycode
\global\pgf@picmaxx=.5\multi@col@width
\global\pgf@picminx=-.5\multi@col@width
\ifnum\multi@col@count=1\relax
\global\let\pgfmatrixemptycode=\orig@pgfmatrixemptycode
\fi
}
}
}
\makeatother

\begin{document}
\begin{tikzpicture}{
\matrix[matrix of nodes, nodes={draw}, draw=black] (Layers) {
%row 1
|[multicol=4]| A &&&&|[multicol=3]| B && \\
%row 2
|[multicol=3]| &&&|[multicol=2]| C &&|[multicol=2]| & \\
%row 3
D &|[multicol=2]| E &&|[multicol=2]| F && G & H \\
%row 4
& I &|[multicol=4]| &&& \\
%row 5
|[multicol=2]| J &&|[multicol=4]| K &&&& L \\
};
}
\end{tikzpicture}
\end{document}


However, the result is somewhat dissatisfying (unwanted boxes appear in some of the empty spaces, and boxes around letters are not stretched wide enough):

Despite the dissatisfying result I achieved so far, I tried adapting it into a more visually appealing version (just replace the \begin{tikzpicture}...\end{tikzpicture} part in the MWE):

\begin{tikzpicture}[
base/.style={
rounded corners,
font={\sffamily\bfseries},
align=center,
},
block/.style={
base,
draw=lime,
fill=blue,
font={\sffamily\bfseries\color{white}},
},]{
\matrix[draw=black] (Layers) {
%row 1
|[multicol=4]|
\node[block] (a) {A};
&&&&|[multicol=3]|
\node[block] (b) {B};
&& \\
%row 2
|[multicol=3]| &&&|[multicol=2]|
\node[block] (c) {C};
&&|[multicol=2]| & \\
%row 3
\node[block] (d) {D};
&|[multicol=2]|
\node[block] (e) {E};
&&|[multicol=2]|
\node[block] (f) {F};
&&
\node[block] (g) {G};
&
\node[block] (h) {H};
\\
%row 4
&
\node[block] (i) {I};
&|[multicol=4]| &&& \\
%row 5
|[multicol=2]|
\node[block] (j) {J};
&&|[multicol=4]|
\node[block] (k) {K};
&&&&
\node[block] (l) {L};
\\
};
}
\end{tikzpicture}


This results in the following:

Quite clearly, most of the boxes are not properly stretched to their intended size. How do I fix that?

-
Have a look at texample.net/tikz/examples/feature/matrices If you can give an example of your tryings, somebody might be able to extend it. Section 5.3 of the pgf-manual could be useful, too (Aligning nodes using matrices). – Johannes_B Dec 10 '13 at 13:54
You can also achieve this effect using \framebox and \makebox, using \rule or \vphantom or \raisebox to produce the vertical size. – John Kormylo Dec 10 '13 at 14:51
I have updated the question to include an attempt at tackling the problem using tikz matrices, but the result is rather dissatisfying. Any hints to fixing that will be greatly appreciated. – derabbink Dec 11 '13 at 8:49
So you don't actually want to print out the numbers in the blank area? That simplifies things. – John Kormylo Dec 11 '13 at 15:27

I based this on 12cm of blocks and 4mm of slop, then fudged the blocks to get things to line up better.

\documentclass{article}

\newlength{\cellH}% cell height
\setlength{\cellH}{.8cm}

\newlength{\cellW}% cell width (1 unit)
\setlength{\cellW}{.8cm}

\newlength{\cellM}% (cell height - character height)/2
\settoheight{\cellM}{ABCDEFGHIJKL12345}
\setlength{\cellM}{-0.5\cellM}

\newcommand{\cell}[2]% #1 = width, #2 = text
{\framebox[#1\cellW][c]{\raisebox{\cellM}[\cellH]{#2}}}

\newcommand{\blank}[2]% #1 = width, #2 = text
{\makebox[#1\cellW][c]{\raisebox{\cellM}[\cellH]{#2}}}

\begin{document}

\centering{\parbox{12.4\cellW}{%
\cell{7.65}{A} \cell{4.65}{B}
\blank{6}{1} \cell{3}{C} \blank{3}{2}
\cell{2}{D} \cell{3}{E} \cell{3}{F} \cell{2}{G} \cell{2}{H}
\blank{2}{3} \cell{2}{I} \blank{6.1}{4} \blank{2}{5}
\cell{4.1}{J} \cell{6.1}{K} \cell{2}{L}
\rule{12\cellW}{0pt}% right justify last line (I miss \hshrink)
}}


\end{document}

And here is a version using Tikz. Using "above right" puts the (x,y) location on the lower left corner, rather than in the center.

\documentclass{article}
\usepackage{tikz}

\newlength{\cellH}% cell height
\setlength{\cellH}{.8cm}

\newlength{\cellW}% cell width (1 unit)
\setlength{\cellW}{.8cm}

\newcommand{\cell}[3]% #1 = border, #2 = width, #3 = text
{node[draw=#1,minimum width=#2\cellW]{#3}}

\pgfsetxvec{\pgfpoint{\cellW}{0cm}}% x coordinate
\pgfsetyvec{\pgfpoint{0cm}{\cellH}}% y coordinate

\begin{document}
\begin{center}
\begin{tikzpicture}
\path[every node/.style={minimum height=\cellH, above right}]
(0,4.4) \cell{black}{7.65}{A}
(7.75,4.4) \cell{black}{4.65}{B}
(0,3.3) \cell{white}{6}{1}
(6.2,3.3) \cell{black}{3}{C}
(9.4,3.3) \cell{white}{3}{2}
(0,2.2) \cell{black}{2}{D}
(2.1,2.2) \cell{black}{3}{E}
(5.2,2.2) \cell{black}{3}{F}
(8.3,2.2) \cell{black}{2}{G}
(10.4,2.2) \cell{black}{2}{H}
(0,1.1) \cell{white}{2}{3}
(2.1,1.1) \cell{black}{2}{I}
(4.2,1.1) \cell{white}{6.1}{4}
(10.4,1.1) \cell{white}{2}{5}
(0,0) \cell{black}{4.1}{J}
(4.2,0) \cell{black}{6.1}{K}
(10.4,0) \cell{black}{2}{L};
\end{tikzpicture}
\end{center}
\end{document}


-
This looks quite promising. Is there a way to do it with a dynamic size as well? – derabbink Dec 10 '13 at 19:34
Sure, replace "cm" with some length "\myunit" (for example). I made the vertical size font dependent. – John Kormylo Dec 10 '13 at 23:51
probably the cleanest way to scale it dynamically would be to produce some kind of \myunit depending on the current available width, right before the picture is to be rendered. But that seems tricky... – derabbink Dec 11 '13 at 8:52
Am revising both versions. (One done. One to go.) If you know what you unscaled width is, you can divide \linewidth (the current available space) by that. – John Kormylo Dec 11 '13 at 14:16
In this case, use .081\linewidth – John Kormylo Dec 11 '13 at 14:45

I was not 100% satisfied with @John Kormylo's answer, so I kept digging for a solution.
This answer by @Qrrbrbirlbel referred to a TikZ library named "node-families" (download here) which introduces new keys to style \nodes: In particular Minimum Width=someAlias which makes sure that all nodes with that property will have the same minimum width (and effectively the same total width, if other style-options are the same).

And here's my solution (MWE):

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{positioning,node-families,calc,matrix,fit}

\begin{document}
\begin{center}
\begin{tikzpicture}[node distance=3pt,
base/.style={
rounded corners,
font={\sffamily\bfseries},
align=center,
},
block/.style={
base,
draw=black,
fill=orange,
font={\small\sffamily\bfseries\color{white}},
inner sep=3pt,
},
overlap/.style={
minimum width=1.5em,
%draw=red, %enable to aid during construction
},
group/.style={
inner sep=0,
%draw=black, %enable to aid during construction
},]{
{%row3
\node[block, Minimum Height=row3] (d) {D};
\node[block, right=of d, Minimum Height=row3, Minimum Width=e_iIOverlapRGroup] (e) {E};
\node[block, right=of e, Minimum Height=row3, Minimum Width=cOverlapGroup_c_f] (f) {F};
\node[block, right=of f, Minimum Height=row3] (g) {G};
\node[block, right=of g, Minimum Height=row3, Minimum Width=h_l] (h) {H};
}
{%row2
\node[block, above=of f, Minimum Height=row2, Minimum Width=cOverlapGroup_c_f] (c) {C};
}
{%row1
%helper nodes
\node[overlay, above=of c.north west, anchor=south west, Minimum Height=row1] (cOverlapL) {};
\node[overlay, right=of cOverlapL, Minimum Height=row1] (cOverlapR) {};
\node[group, fit=(cOverlapL)(cOverlapR), above=of c, Minimum Height=row1, Minimum Width=cOverlapGroup_c_f] (cOverlapGroup) {};
%block nodes
\node[block, left=of cOverlapGroup.center, xshift=1.5pt, Minimum Height=row1, Minimum Width=a_aDGroup] (a) {A};
\node[block, right=of a, Minimum Height=row1, Minimum Width=b_bAGroup] (b) {B};
%more helper nodes
\node[group, fit=(b)(h), Minimum Width=b_bAGroup] (bHGroup) {};
}
{%row4
%block nodes
\node[block, below=of e.south west, anchor=north west, Minimum Height=row4] (i) {I};
%helper nodes
\node[overlap, right=of i, Minimum Height=row4] (iOverlapR) {};
\node[group, fit=(i)(iOverlapR), below=of e, Minimum Height=row4, Minimum Width=e_iIOverlapRGroup] (iIOverlapRGroup) {};
\node[group, fit=(d)(i), Minimum Width=dIGroup_j] (dIGroup) {};
\node[group, fit=(iOverlapR)(g), Minimum Width=iOverlapRGGroup_k] (iOverlapRGGroup) {};
}
{%row5
\node[block, below=of dIGroup, Minimum Height=row5, Minimum Width=dIGroup_j] (j) {J};
\node[block, right=of j, Minimum Height=row5, Minimum Width=iOverlapRGGroup_k] (k) {K};
\node[block, right=of k, Minimum Height=row5, Minimum Width=h_l] (l) {L};
}
}
\end{tikzpicture}
\end{center}
\end{document}


Like @Qrrbrbirlbel describes, though, using these properties requires you to compile your document a few times. For me, this is not a problem, since my document must be compiled a few times any way in order to get all (cross) references, appendices, etc. right.
Below, you can see the three runs required for my example to come out right:

1st run:

2nd run:

3rd run:

-