What's the best way to produce a matrix with labels that are nested in braces, like this:
3 Answers
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}
-
4
-
+1 just for the unknown (at least for me)
execute at empty cell
. Oct 24, 2012 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}[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}
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 \tikzmark
s 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 theC
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 theetoolbox
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}
-
Maybe put it inside a
\begin{bmatrix} ... \end{bmatrix}
or\left[ \right]
to draw the delimiters with a few\!
here and there?– percusseOct 24, 2012 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. Oct 24, 2012 at 19:00
\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.