Matrix with labels nested in braces

What's the best way to produce a matrix with labels that are nested in braces, like this: • Welcome to TeX.sx! Please add a minimal working example (MWE) that illustrates your problem. – percusse Oct 23 '12 at 23:03
• Thanks to all for the great answers. For future reference, how should I provide a MWE for a question of this sort? – Noam Ross Oct 24 '12 at 18:25
• Just a document starting from \documentclass{article} to \end{document} with bare essentials, say with matrix typed in etc. is sufficient. We don't ask for much. You can also check for other questions for examples. – percusse Oct 24 '12 at 19:36

In today's I have too much free time episode we will attack a question posted without a MWE. Absence of a MWE gives us the right to go as esoteric as possible hence here is one Tweak this, tweak that possibility.

\documentclass[tikz]{standalone}
\usetikzlibrary{matrix,trees}

\begin{document}
\begin{tikzpicture}[level distance=7mm,
level 1/.style={sibling distance=8mm},
level 2/.style={sibling distance=4mm},
]
\matrix (m) [mymatrix/.style={execute at empty cell=
\ifnum\pgfmatrixcurrentrow<5
\ifnum\pgfmatrixcurrentcolumn>4
\node\bgroup$0$\egroup;\fi
\else
\ifnum\pgfmatrixcurrentcolumn<5
\node\bgroup$0$\egroup;\fi
\fi
},mymatrix,
right delimiter={]},left delimiter={[}]{
&&&&&&&\\
&&&&&&&\\
&&&&&&&\\
&&&&&&&\\
&&&&&&&\\
&&&&&&&\\
&&&&&&&\\
&&&&&&&\\
};
\begin{scope}[edge from parent path=
{(\tikzparentnode.south) .. controls +(0,-0.2) and +(0,0.2)
.. (\tikzchildnode.north)}]
\node at ([yshift=1.5cm]m.67) {$A$}
child {node {$1$}
child {node {S}}
child {node {I}}}
child {node {$2$}
child {node {S}}
child {node {I}}
};
\node at ([yshift=1.5cm]m.113) {$B$}
child {node {$1$}
child {node {S}}
child {node {I}}}
child {node {$2$}
child {node {S}}
child {node {I}}
};
\end{scope}

\begin{scope}[edge from parent path=
{(\tikzparentnode.east) .. controls +(0.2,0) and +(-0.2,0)
.. (\tikzchildnode.west)},level distance=6mm,
level 1/.style={sibling distance=9.2mm},
level 2/.style={sibling distance=4.5mm}]
\node at ([xshift=-1.6cm]m.152) {$A$}[grow=right]
child {node {$1$}
child {node {S}}
child {node {I}}}
child {node {$2$}
child {node {S}}
child {node {I}}
};
\node at ([xshift=-1.6cm]m.-152) {$B$}[grow=right]
child {node {$1$}
child {node {S}}
child {node {I}}}
child {node {$2$}
child {node {S}}
child {node {I}}
};
\end{scope}
\end{tikzpicture}
\end{document} • +1: Beautiful! TeX is incredible but TeX users are better. – Sigur Oct 24 '12 at 1:30
• +1 just for the unknown (at least for me) execute at empty cell. – Claudio Fiandrino Oct 24 '12 at 6:29

Here's another option using the blkarray package for the matrix and \tikzmark for the braces (using decoration=brace):

\documentclass{article}
\usepackage{mathtools}
\usepackage{blkarray}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}

\newcommand{\tikzmark}{%
\tikz[overlay,remember picture,baseline] \node [anchor=base] (#1) {};}

% for horizontal braces
% \myhbrace{<mark>}{<mark>}{<label>}
\newcommand\myhbrace{%
\draw[decorate,decoration={brace,raise=5pt}]
(#1.north) -- node[yshift=13pt] {#3} (#2.north);}

% for vertical braces
% \myvbrace{<mark>}{<mark>}{<label>}
\newcommand\myvbrace{%
\draw[decorate,decoration={brace,raise=6pt,mirror}]
([yshift=3pt]#1.north east) -- node[xshift=-15pt] {#3} ([yshift=3pt]#2.south east);}

\begin{document}

$\begin{blockarray}{ccccccccc} & \tikzmark{a}S & I\tikzmark{b} & \tikzmark{c}S & I\tikzmark{d} & \tikzmark{e}S & I\tikzmark{f} & \tikzmark{g}S & I\tikzmark{h} \\ \begin{block}{l[cccccccc]} \\[-1.2ex] \tikzmark{m}S & & & & & 0 & 0& 0 & 0 \\[.3ex] \tikzmark{n}I & & & & & 0 & 0& 0 & 0 \\[.3ex] \tikzmark{o}S & & & & & 0 & 0& 0 & 0 \\[.3ex] \tikzmark{p}I & & & & & 0 & 0& 0 & 0 \\[.3ex] \tikzmark{q}S & 0 & 0 & 0 & 0 & & & & \\[.3ex] \tikzmark{r}I & 0 & 0 & 0 & 0 & & & & \\[.3ex] \tikzmark{s}S & 0 & 0 & 0 & 0 & & & & \\[.3ex] \tikzmark{t}I & 0 & 0 & 0 & 0 & & & & \\[1ex] \end{block} \end{blockarray}$

\begin{tikzpicture}[overlay,remember picture,baseline]
\myhbrace{a}{b}{$\tikzmark{i}1$}
\myhbrace{c}{d}{$2\tikzmark{j}$}
\myhbrace{e}{f}{$\tikzmark{k}1$}
\myhbrace{g}{h}{$2\tikzmark{l}$}
\myhbrace{i}{j}{$A$}
\myhbrace{k}{l}{$B$}

\myvbrace{m}{n}{$\tikzmark{u}1$}
\myvbrace{o}{p}{$\tikzmark{v}2$}
\myvbrace{q}{r}{$\tikzmark{w}1$}
\myvbrace{s}{t}{$\tikzmark{x}2$}
\myvbrace{u}{v}{$A$}
\myvbrace{w}{x}{$B$}

\node[yshift=15pt,font=\small] at (m|-k) {$i=$};
\node[yshift=2.5pt,font=\small] at (m|-k) {$j=$};
\node[yshift=4pt,font=\small] at (m|-a) {$k=$};
\end{tikzpicture}

\end{document} The code has to be processed three times for the elements to stabilize.

Continuing on in percusse's tradition, here is a slight improvement on the version provided by Gonzalo Medina.

I have used the collcell package to automate the insertion of the appropriate \tikzmark into the matrix. This makes the matrix a bit more easier to read as it is not cluttered with all the numerous \tikzmarks required for this application to yield: Notes:

• I have added an optional first parameter to the \myhbrace and \myvbrace to allow one to specify the parameters for the \draw command.
• Other than the above change, and the manual drawing of the matrix border (see Further Enhancements below), the calls to the two brace commands are one to one equivalent to Gonzalo's, with the name changed to something more meaningful (since they are automatically inserted).
• Two new column types are defined here. The first column (and only the first) must use the F column type. This allows me to recognize when a new row is started. All others must use the C column type.
• Unlike most of the other applications of \tikzmark, this actually requires three (not two) runs. First two to determine the locations, and the third to do the drawing.
• I have used newtoggle from the etoolbox package as I prefer that syntax versus the \newif syntax. But if you don't want to include an additional package it should be pretty straightforward to adapt this to use \newif or some other conditional methods
• Similarly, I used the xstring package for numerical comparrison, and again this could be done without this package if that was an issue.

Further Enhancements:

• I am not happy about the fact that I had to manually draw the matrix border. It turns out that the matrix macros do not seem to allow the use of \newcolumntype. I only realized this when I was done with everything else, so was too far into it to not finish it!!

Code:

\documentclass{article}
\usepackage{mathtools}
\usepackage{blkarray}
\usepackage{tikz}
\usetikzlibrary{calc,decorations.pathreplacing}

\usepackage{collcell}
\usepackage{etoolbox}
\usepackage{xstring}

% The "F" column type is to ONLY be used for the first column
\newcolumntype{F}{>{\collectcell\NewRowData}{c}<{\endcollectcell}}
\newcolumntype{C}{>{\collectcell\NewColumnData}{c}<{\endcollectcell}}

\newcounter{RowCount}
\newcounter{ColumnCount}

\newcommand*{\NewColumnData}{%
\stepcounter{ColumnCount}%
\tikzmark{Col \arabic{ColumnCount} Left}%
}{}%
#1%
\tikzmark{Col \arabic{ColumnCount} Right}%
}%
}%
\newcommand*{\NewRowData}{%
\setcounter{ColumnCount}{-1}% start a new row ==> at first column
%
\stepcounter{RowCount}%
\tikzmark{Row \arabic{RowCount}}%
}{}%
\NewColumnData{#1}%
}%

\newcommand{\tikzmark}{%
\tikz[overlay,remember picture,baseline] \node [anchor=base] (#1) {};}

% for horizontal braces
% \myhbrace[<draw options>]{<mark>}{<mark>}{<label>}
\newcommand\myhbrace[]{%
\draw[decorate,decoration={brace,raise=5pt}, #1]
(#2.north) -- node[yshift=13pt] {#4} (#3.north);}

% for vertical braces
% \myvbrace[<draw options>]{<mark>}{<mark>}{<label>}
\newcommand\myvbrace[]{%
\draw[decorate,decoration={brace,raise=6pt,mirror}, #1]
([yshift=3pt]#2.north east) -- node[xshift=-15pt] {#4} ([yshift=3pt]#3.south east);}

\begin{document}

$\begin{array}{FCCCCCCCC} & S & I & S & I & S & I & S & I \\ S & & & & & 0 & 0 & 0 & 0 \\[.3ex] I & & & & & 0 & 0 & 0 & 0 \\[.3ex] S & & & & & 0 & 0 & 0 & 0 \\[.3ex] I & & & & & 0 & 0 & 0 & 0 \\[.3ex] S & 0 & 0 & 0 & 0 & & & & \\[.3ex] I & 0 & 0 & 0 & 0 & & & & \\[.3ex] S & 0 & 0 & 0 & 0 & & & & \\[.3ex] I & 0 & 0 & 0 & 0 & & & & \\[1ex] \end{array}$

\begin{tikzpicture}[overlay,remember picture,baseline]
\myhbrace[violet, thick]{Col 1 Left}{Col 2 Right}{$\tikzmark{Col 1-2}1$}
\myhbrace[violet, thick]{Col 3 Left}{Col 4 Right}{$2\tikzmark{Col 3-4}$}
\myhbrace[violet, thick]{Col 5 Left}{Col 6 Right}{$\tikzmark{Col 5-7}1$}
\myhbrace[violet, thick]{Col 7 Left}{Col 8 Right}{$2\tikzmark{Col 7-8}$}
\myhbrace[orange, thick]{Col 1-2}{Col 3-4}{$A$}
\myhbrace[orange, thick]{Col 5-7}{Col 7-8}{$B$}

\myvbrace[red,  thick]{Row 1}{Row 2}{$\tikzmark{Row 1-2}1$}
\myvbrace[red,  thick]{Row 3}{Row 4}{$\tikzmark{Row 3-4}2$}
\myvbrace[red,  thick]{Row 5}{Row 6}{$\tikzmark{Row 5-6}1$}
\myvbrace[red,  thick]{Row 7}{Row 8}{$\tikzmark{Row 7-8}2$}
\myvbrace[blue, thick]{Row 1-2}{Row 3-4}{$A$}
\myvbrace[blue, thick]{Row 5-6}{Row 7-8}{$B$}

\node[yshift=15pt, font=\small] at (Row 1 |- Col 5-7)    {$i=$};
\node[yshift=2.5pt,font=\small] at (Row 1 |- Col 5-7)    {$j=$};
\node[yshift=4pt,  font=\small] at (Row 1 |- Col 1 Left) {$k=$};

% Draw the lines for the matrix
\newcommand*{\XShift}{0.3em}
\newcommand*{\YShift}{0.5ex}

\coordinate (topLeft) at (Col 1 Left);
\coordinate (botLeft) at (topLeft |- Row 8);

\coordinate (topRight) at (Col 8 Right);
\coordinate (botRight) at (topRight |- Row 8);

\draw [black, line width=1.2pt]% Left matrix line
([shift={(0.3*\XShift,-\YShift)}]topLeft) --
([shift={(-\XShift,-\YShift)}]topLeft)  |- ([shift={(-\XShift,-1.5*\YShift)}]botLeft)
-- ++(1.3*\XShift,0);

\draw [black, line width=1.2pt]% Right matrix line
([shift={(-0.3*\XShift,-\YShift)}]topRight) --
([shift={( \XShift,-\YShift)}]topRight) |- ([shift={( \XShift,-1.5*\YShift)}]botRight)
-- ++(-1.3*\XShift,0);
\end{tikzpicture}
\end{document}
• Maybe put it inside a \begin{bmatrix} ... \end{bmatrix} or \left[ \right] to draw the delimiters with a few \! here and there? – percusse Oct 24 '12 at 10:07
• @percusse: It seems that the matrix environment do not allow for the use of \newcolumntype. I also did try the \left[ \right] but that required me to tweak the spacing in between the columns as it would only be applied to the sub-matrix. – Peter Grill Oct 24 '12 at 19:00