[Tex/LaTex] How to draw horizontal and vertical lines for a TikZ matrix

tikz-matrixtikz-pgf

I want to use a TikZ matrix to draw a table with empty cells. But no matter what I do I run into errors. In particular, LaTeX complains about

! Package pgf Error: No shape named ae-5-4 is known.

Here's the code (far from what I really want):

\documentclass{article}
\usepackage[margin=0.5in]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{decorations.pathreplacing}
\begin{document}

\begin{tikzpicture}[
    %%---------------------------------------
    dm/.style={decoration={brace,mirror},decorate},
    dd/.style={decoration={brace},decorate},
    %%---------------------------------------
    nlble/.style={inner sep=0pt,anchor=east},
    nlblw/.style={inner sep=0pt,anchor=west},
    %%---------------------------------------
  ]
  \matrix (ae) [matrix of nodes,
                column 1/.style={anchor=west},
                minimum width=2cm,
                column sep=2.5ex,
                row sep=2.5ex,
                matrix of nodes/.style={execute at empty cell=\node {AAA};}
                ]
  {
        & column A & column B & column C & g                 \\
  Row A &          &          &          & a \node (cc)  {}; \\
  Row B &          &          &          &   \node (ss)  {}; \\
  Row C &          &          &          &   \node (alt) {}; \\
  Row D &          &          &          &                   \\
  };
  \foreach \row in {1,2,3,4,5} {%
    \draw[blue,line width=0.4pt] ($(ae-\row-2.base west)-(0,2ex)$) -- ($(ae-\row-4.base east)-(0,2ex)$);
   }
%  \foreach \col in {1,2,3,4}{%
%    \draw[blue,line width=0.4pt] ($(ae-1-\col.base east)-(0,2ex)$) -- ($(ae-4-\col.base east)-(0,2ex)$);
%  }
  \draw[dm]  ($(ae-2-1.west)+(0,2.5ex)$) -- ($(ae-3-1.west)-(0,2.5ex)$) node [midway,anchor=east] (A) {};
  \draw[dm]  ($(ae-4-1.west)+(0,2.5ex)$) -- ($(ae-4-1.west)-(0,2.5ex)$) node [midway,anchor=east] (B) {};
  \draw[dd]  ($(cc.east)+(0,2.5ex)$)     -- ($(cc.east)+(0,-2.5ex)$)    node [midway,anchor=west] (C) {};
  \draw[dd]  ($(ss.east)+(0,2.5ex)$)     -- ($(alt.east)+(0,-2.5ex)$)   node [midway,anchor=west] (D) {};

  \node[nlble] at ($(A)+(-1ex,0)$) {\parbox{1.35in}{\footnotesize\centering Instructions for material to be put in Rows A and B.}};
  \node[nlble] at ($(B)+(-1ex,0)$) {\parbox{1.35in}{\footnotesize\centering Instructions for material to be put in Row C.}};
  \node[nlblw] at ($(C)+(1ex,0)$)  {\parbox{1.5in}{\footnotesize\centering Additional instructions for Row A.}};    
  \node[nlblw] at ($(D)+(1ex,0)$)  {\parbox{1.5in}{\footnotesize\centering Additional instructions for Rows B and C.}};    
\end{tikzpicture}

\end{document}

What I'm most interested in knowing is how to automate drawing horizontal and vertical lines. I'd prefer to do it using the node names that TikZ creates for the cells of a matrix.

Of secondary interest,

  • I would like to know why when I try to add text before the \node {cc}; in the last column of Row A, I get an undefined command error from LaTeX.
  • I would also like to know whether there's a way to define the style for a range of columns (such as columns 2, 3, and 4) without having to declare the style for each individual column or define a style universally for all columns. For example, I only want to set the minimum width for columns 1, 2, and 3.

Best Answer

There are a few things going awry with your code.

  1. When you do matrix of nodes then each cell is surrounded by \node[options] (<name>) { ... };. It isn't allowed to nest nodes, so your \node ... in cell 5-2 is illegal. The ones in 5-3 and 5-4 are okay because TikZ takes a look to see if the cell starts with a TikZ command before enclosing it in a node. As the nodes are already there, if you want simply to give them new names then use the syntax for specifying extra options: |[options]| at the start of the cell.

  2. Although you want to give them new names, I think that you also want to refer to them via the ae-m-n syntax. So you actually want to give them aliases. Thus use the alias=<name> key.

  3. The line matrix of nodes/.style={execute at empty cell=\node {AAA};} is bizarre. It overwrites the matrix of nodes style, but you've already executed this. I presume that what you want is for AAA to appear in each blank cell. I don't know if there is a way to do this without hacking the code a little (ie without a \makeatletter) but a simple hack to adjust the code for empty cells solves this. I suspect that there are a couple of cells that you want to be genuinely empty. Putting {} as their contents makes them officially not empty (so doesn't invoke the empty cell code) whilst still being actually empty.

Here's a modification of your code taking the above into account:

\documentclass{article}
%\url{http://tex.stackexchange.com/q/134209/86}
\usepackage[margin=0.5in]{geometry}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{matrix}
\usetikzlibrary{decorations.pathreplacing}

\makeatletter
\newcommand\myemptycell[1]{%
  \iftikz@lib@matrix@empty\node[name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn] {#1};\fi}
\makeatother
\begin{document}

\begin{tikzpicture}[
    %%---------------------------------------
    dm/.style={decoration={brace,mirror},decorate},
    dd/.style={decoration={brace},decorate},
    %%---------------------------------------
    nlble/.style={inner sep=0pt,anchor=east},
    nlblw/.style={inner sep=0pt,anchor=west},
    %%---------------------------------------
  ]
  \matrix (ae) [matrix of nodes,
                column 1/.style={anchor=west},
                minimum width=2cm,
                column sep=2.5ex,
                row sep=2.5ex,
                nodes in empty cells,
                execute at empty cell=\myemptycell{AAA},
                ]
  {
   {}   & column A & column B & column C & g                 \\
  Row A &          &          &          &|[alias=cc]| a \\
  Row B &          &          &          &|[alias=ss]| \\
  Row C &          &          &          &|[alias=alt]| \\
  Row D &          &          &          &               {}    \\
  };
  \foreach \row in {1,2,3,4,5} {%
    \draw[blue,line width=0.4pt] ($(ae-\row-2.base west)-(0,2ex)$) -- ($(ae-\row-4.base east)-(0,2ex)$);
   }
%  \foreach \col in {1,2,3,4}{%
%    \draw[blue,line width=0.4pt] ($(ae-1-\col.base east)-(0,2ex)$) -- ($(ae-4-\col.base east)-(0,2ex)$);
%  }
  \draw[dm]  ($(ae-2-1.west)+(0,2.5ex)$) -- ($(ae-3-1.west)-(0,2.5ex)$) node [midway,anchor=east] (A) {};
  \draw[dm]  ($(ae-4-1.west)+(0,2.5ex)$) -- ($(ae-4-1.west)-(0,2.5ex)$) node [midway,anchor=east] (B) {};
  \draw[dd]  ($(cc.east)+(0,2.5ex)$)     -- ($(cc.east)+(0,-2.5ex)$)    node [midway,anchor=west] (C) {};
  \draw[dd]  ($(ss.east)+(0,2.5ex)$)     -- ($(alt.east)+(0,-2.5ex)$)   node [midway,anchor=west] (D) {};

  \node[nlble] at ($(A)+(-1ex,0)$) {\parbox{1.35in}{\footnotesize\centering Instructions for material to be put in Rows A and B.}};
  \node[nlble] at ($(B)+(-1ex,0)$) {\parbox{1.35in}{\footnotesize\centering Instructions for material to be put in Row C.}};
  \node[nlblw] at ($(C)+(1ex,0)$)  {\parbox{1.5in}{\footnotesize\centering Additional instructions for Row A.}};    
  \node[nlblw] at ($(D)+(1ex,0)$)  {\parbox{1.5in}{\footnotesize\centering Additional instructions for Rows B and C.}};    
\end{tikzpicture}

\end{document}

With result:

Matrix with lines