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

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}

matrix of cells with horizontal lines


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}

enter image description here

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:

hlines and tikz matrices

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-\[email protected] west) edge[\csname hline@row@\hline@row\endcsname] (\tikzlastnode-cell-\hline@row-\[email protected] 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}