Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

What's the best way to produce a matrix with labels that are nested in braces, like this: enter image description here

share|improve this question
1  
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

3 Answers 3

up vote 20 down vote accepted

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}

enter image description here

share|improve this answer
4  
+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
    
+1 for your nice words. –  percusse Oct 24 '12 at 11:10

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:

enter image description here

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}
\newtoggle{DoneWithHeader}
\togglefalse{DoneWithHeader}
\newcommand{\DoneWithHeader}{\global\toggletrue{DoneWithHeader}}

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



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

% for horizontal braces
% \myhbrace[<draw options>]{<mark>}{<mark>}{<label>}
\newcommand\myhbrace[4][]{%
\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[4][]{%
  \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}
share|improve this answer
    
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

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}[1]{%
  \tikz[overlay,remember picture,baseline] \node [anchor=base] (#1) {};}

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

% for vertical braces
% \myvbrace{<mark>}{<mark>}{<label>}
\newcommand\myvbrace[3]{%
  \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}

enter image description here

The code has to be processed three times for the elements to stabilize.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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