Tikz: Align left/width of different fit boxes so multiple fitboxes align nicely vertically

The Tikz fit functionality is very nice, but what (1) if I want to align multiple fit boxes to the same left/width location so that all fit boxes matches, so different fit boxes are nicely aligned vertically?

And (2) (more advanced), can I also dynamically control the spacing between the fitboxes? So this requires to change for children from canvas coordinate space to parent (fitbox) coordinate space, and then layout all fitboxes according certain properties (spacing between box the same).

PS: For this simple case you can off course come up with some simple solutions like an extra invisible node in top/bottom fitbox to get everything aligned, but this off course does not work when the fitboxes get complexer content.

A picture to clarify:

MWE:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{fit}
\begin{document}
\begin{tikzpicture}[>=stealth',semithick,auto]
\tikzstyle{surround} = [fill=blue!10,thick,draw=black,rounded corners=2mm]
\tikzstyle{obj}  = [circle, minimum width=10pt, draw, inner sep=0pt]
\node[obj] (id1) at (2,2)  {};
\node[obj] (id2) at (2,3) {};
\node[obj] (id3) at (2.5,3) {};
\node[obj] (id4) at (2.5,4) {};
\begin{pgfonlayer}{background}
\node[surround] (background) [fit = (id1)] {};
\node[surround] (background) [fit = (id2)(id3)] {};
\node[surround] (background) [fit = (id4)] {};
\end{pgfonlayer}
\end{tikzpicture}
\end{document}


Next code shows a solution for your first problem. You want similar fitting nodes, then if you build them with similar inner nodes, they will have same size.

As an example

   \node[surround, fit = (id1)(id3.east|-id1.center)] {};


will build a node big enough for id1 (which fixes height and western border) but it will also encompass coordinate id3.east|-id1.center which will fix eastern border.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{fit}
\begin{document}
\begin{tikzpicture}[>=stealth',semithick,auto,
surround/.style={fill=blue!10,thick,draw=black,rounded corners=2mm},
obj/.style={circle, minimum width=10pt, draw, inner sep=0pt}]
\node[obj] (id1) at (2,2)  {};
\node[obj] (id2) at (2,3) {};
\node[obj] (id3) at (2.5,3) {};
\node[obj] (id4) at (2.5,4) {};
\begin{scope}[on background layer]
\node[surround, fit = (id2)(id3)] {};
\node[surround, fit = (id1)(id3.east|-id1.center)] {};
\node[surround, fit = (id4)(id2.west|-id4.center)] {};
\end{scope}
\end{tikzpicture}
\end{document}


Update: Fixed distance between fitting nodes.

I don't know if this solution will server, but in case you already know how big are your fitting nodes, you can draw them where you want and fill with objects later:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds,positioning}
\usetikzlibrary{shapes}
\usetikzlibrary{arrows}
\usetikzlibrary{fit}
\begin{document}
\begin{tikzpicture}[>=stealth',semithick,auto,
surround/.style={fill=blue!10,thick,draw=black,rounded corners=2mm},
obj/.style={circle, minimum width=10pt, draw, inner sep=0pt}]

\node[obj] (id2) at (2,3) {};
\node[obj] (id3) at (2.5,3) {};
\begin{scope}[on background layer]
\node[surround, fit = (id2)(id3)] (fit1) {};
\node[surround, fit = (id2)(id3), above=5mm of fit1] (fit2) {};
\node[surround, fit = (id2)(id3), below=15mm of fit1] (fit3) {};
\end{scope}
\node[obj] (id1) at (fit2-|id2)  {};
\node[obj] (id1) at (fit3-|id3)  {};
\end{tikzpicture}
\end{document}


3rd version: with matrix of nodes

If your obj follow a more or less regular distribution, instead of fitting them, you can draw matrix of nodes. If all matrix contains the same number of columns, all of them will have the same width and it's height will be fixed with the number of present rows. And as matrix are regular nodes, you can fix distance between them.

A little example:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix,positioning,arrows}
\begin{document}
\begin{tikzpicture}[>=stealth',semithick,auto,
surround/.style={fill=blue!10, thick, draw=black,
rounded corners=2mm, matrix of nodes, nodes in empty cells, nodes={obj}, column sep=3pt, row sep=3pt},
obj/.style={circle, minimum width=10pt, draw, inner sep=0pt}]

\matrix[surround] (A) {& |[draw=none]| &\\
|[draw=none]| & &|[draw=none]|\\};
\matrix[surround, below=.5 of A] (B) { & &|[draw=none]|\\};
\matrix[surround, below=.5 of B] (C) {& \\& |[draw=none]| &\\};
\end{tikzpicture}
\end{document}


• This last snippet is indeed really cool. HOWEVER now fit2 and fit3 have also the height of fit1. This is not what I always want. Is it possible to have fit2/fit3 have match fit1 in width but not in height? Jul 31 '15 at 12:13
• @jos you can always do something like fit = {(id2)([yshift=1cm]id3.east)} which will keep width but noth height. Although I'm not sure about what do you want to do and if this is the best (or easier) solution. I think is easier to draw several outer nodes with your desired size and place obj inside. Another solution could be to use .pics. If you could explain the problem in more datail or show a more complex example, we could help you better. Jul 31 '15 at 12:48
• @jos Does your objects follow a regular (matrix) distribution? Jul 31 '15 at 12:53