# Horizontal row separation line in tikz matrix (like \hline in tabular)

In this question tikz-matrix-as-a-replacement-for-tabular a nice solution was given to let the matrix in tikz behave like tabular.

In this solution cell/.style={rectangle} was used to draw lines around every cell. But usually, however, I'd rather not give my tables this "grid"-look.

Is there a way within the tikz matrix to draw horizontal lines between rows that essentially behave like \hline within tabular?

I know I could put a node in the first and final cell of a row and draw a line between them, but this is not really handy compared to a single command like \hline and not very automated either.

-

You can use a style that uses execute at end cell to draw a horizontal line at the top or bottom edge of selected cells. By applying this style to complete using row <number>/.style, you can get an effect similar to \hline:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\begin{document}

\tikzset{toprule/.style={%
execute at end cell={%
\draw [line cap=rect,#1] (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.north west) -- (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.north east);%
}
},
bottomrule/.style={%
execute at end cell={%
\draw [line cap=rect,#1] (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.south west) -- (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.south east);%
}
}
}

\begin{tikzpicture}
\matrix [matrix of nodes,
row sep=-\pgflinewidth,
column sep=-\pgflinewidth,
nodes={rectangle,minimum width=3em,outer sep=0pt},
row 1/.style={toprule=thick,bottomrule},
row 3/.style={bottomrule=thick}]
{
0   & 6 & 5\\
1   & 3 & 7\\
21 & 22 & 23\\
};
\end{tikzpicture}
\end{document}


-
A very nice solution. I like having the option to specify the line width. This gives the whole thing almost the feel of booktabs. –  Martin H Jun 14 '11 at 8:38

The following might at least decrease the burden of putting the nodes etc. (I hope). In fact, it is similar to what you have already ruled out as a bad solution, but still it sweeps the ugliness under the rug and does not introduce new nodes other than the tikz matrix has already defined.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\newcommand{\hhlline}[3]{\draw (#1-#2-1.south west) -- (#1-#2-#3.south east);}
\begin{document}
\begin{tikzpicture}
\node[matrix of math nodes] (mymat) {
0   &a  & 6 \\
1   &b  & 3 \\
2   &c  & 9 \\
};
\hhlline{mymat}{1}{2};
\hhlline{mymat}{2}{3};
\end{tikzpicture}
\end{document}


So, you use the command \hhlline with three arguments, the name of the matrix, the row you want to draw the line under it and the number of columns you want to keep drawing.

I am pretty sure that this can further be improved but I am not very good at accessing the internal variables of the matrix environment and using it inside the command automatically. Anyway, hope it helps. Cheers

And last minute addition: Jake's solution looks quite nice.

-

There is an issue with Jake's code if the nodes are different sizes. This can be fixed using the matrixcells part of the TeX-SX TikZ package (currently available from launchpad) to put the lines in after the matrix has been drawn and positioned correctly. Here's a sample of the code, including an example showing where Jake's code breaks down.

Result:

Code:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usepackage{matrixcells}
\begin{document}

\tikzset{toprule/.style={%
execute at end cell={%
\draw [line cap=rect,#1] (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.north west) -- (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.north east);%
}
},
bottomrule/.style={%
execute at end cell={%
\draw [line cap=rect,#1] (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.south west) -- (\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.south east);%
}
},
}

\makeatletter
\tikzset{
hlines/.style={%
label cells,
initialise hlines,
append after command={%
\pgfextra{\pgfmathtruncatemacro{\hline@cols}{\pgfmatrixcurrentcolumn - 1}}%
\ifx\hline@rows\pgfutil@empty
\else
\foreach \hline@row in \hline@rows {
\pgfextra{\edef\hline@temp{
(\tikzlastnode-cell-\hline@row-1.north west) edge[\csname hline@row@\hline@row\endcsname] (\tikzlastnode-cell-\hline@row-\hline@cols.north east)}}
\hline@temp
}
\fi
}
},
initialise hlines/.code={
\global\let\hline@rows=\pgfutil@empty
\let\hline=\hline@inmatrix
}
}

\newcommand\hline@inmatrix[1][]{%
\ifx\hline@rows\pgfutil@empty
\xdef\hline@rows{\the\pgfmatrixcurrentrow}%
\else
\xdef\hline@rows{\hline@rows,\the\pgfmatrixcurrentrow}%
\fi
\expandafter\xdef\csname hline@row@\the\pgfmatrixcurrentrow\endcsname{#1}%
}
\makeatother

\begin{tikzpicture}
\matrix [matrix of nodes,
row sep=-\pgflinewidth,
column sep=-\pgflinewidth,
nodes={rectangle,minimum width=3em,outer sep=0pt},
row 1/.style={toprule=thick,bottomrule},
row 3/.style={bottomrule=thick}] (a)
{
$$\frac12$$   & 6 & 5\\
1   & 3 & 7\\
21 & 22 & 23\\
};
\matrix [matrix of nodes,hlines,anchor=north] (mm) at (a.south)
{
$$\frac12$$   & 6 & 5\\ \hline[thick]%
1   & 3 & 7\\ \hline
21 & 22 & 23\\
};
\end{tikzpicture}
\end{document}

-
Ah, I love it when solutions to different problems play together like that. Very nice! –  Jake Jun 20 '11 at 7:52
A good hint, thanks for investigating this further –  Martin H Jun 20 '11 at 10:43