12

Is there a simple way to tell TikZ that I want a vertical line to separate the columns of a matrix? I know how to draw them manually, I am looking for an automatic solution, maybe using styles or something.

1
  • 6
    Perhaps mention what you already know, somebody possibly might show another way you might like more before another one could come with a real automatic solution.
    – Stefan Kottwitz
    Jan 22, 2011 at 20:09

4 Answers 4

10

You can use "matrix of nodes" and anchors:

\begin{tikzpicture}
\matrix (mat) [matrix of nodes]
 {
  1 & 2 & 3 \\
  1 & 2 & 3 \\
  1 & 2 & 3 \\
  1 & 2 & 3 \\
 };
% Matrix is called 'mat' first number is row, second numer is column
\draw[thick,red] (mat-1-1.north east) -- (mat-4-1.south east);
\end{tikzpicture}
1
  • 1
    This fails when the entries are of different length.
    – Caramdir
    Nov 27, 2011 at 20:31
6

Here's an example with a matrix of math nodes, with delimiters and a separation line with some shifting for that.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\begin{document}
\begin{tikzpicture}
\matrix (m) [matrix of math nodes,left delimiter=(,right delimiter=),
  inner sep=2pt,outer sep=0pt]{
  a & b & [1em] 0 \\
  c & d & 1 \\ };
\draw ([xshift=0.5em]m-1-2.north east) -- ([xshift=0.5em]m-2-2.south east);
\end{tikzpicture}
\end{document}

matrix example

If the entries would have different width, you could use |- instead of -- to get straight lines, such as

\draw ([xshift=0.5em]m-1-2.north east-|m-2-2.south east) -|
      ([xshift=0.5em]m-2-2.south east);

enter image description here

Even better: set the minimum width property for the nodes in the matrix.

4
  • Like @xeroc's solution this fails when the entries are of different size.
    – Caramdir
    Nov 27, 2011 at 20:32
  • @Caramdir I added a modification regarding this.
    – Stefan Kottwitz
    Nov 27, 2011 at 20:45
  • I think what @Caramdir is referring to is the cases such as the left lower entry is changed with e.g. an integral while keeping the matrix identical. Then the bar is slightly shorter but similar to your solution you can replace it by \draw([xshift=0.2em]m.north west -| m-1-2.east) to ([xshift=0.2em] m.south east -| m-2-2.east); In other words, using the matrix node itself to get the top and bottom correctly.
    – percusse
    Nov 27, 2011 at 21:04
  • @percusse I was only thinking of the width of the nodes, but you are right that the height also needs to be taken into account.
    – Caramdir
    Nov 27, 2011 at 23:00
6

Here's an answer based on answers given at Obstacles to simulating an amsmath matrix by a TiKZ matrix of math nodes and How can I set the background color of the rows and columns of a matrix node in Tikz? You don't specify in the question what type of matrix you are wanting to typeset, so I've simply gone for a similar matrix to that which Stefan and xeroc have used. Exactly what code you need depends a lot on what your matrix code looks like. The only one that you really need is the code from How can I set the background color of the rows and columns of a matrix node in Tikz? The others are there to make it look more impressive.

If the code from How can I set the background color of the rows and columns of a matrix node in Tikz? were in a package (below called tikzamsmatrix), the document would look like this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix,decorations}
\usepackage{calligraphy}
\usepackage{matrixcells}
\usepackage{tikzamsmatrix}

\begin{document}
\[
\begin{tikzamatrix}
a & b & 0 \\
c & a + c & {\displaystyle \int_0^1 \sin(x) d x}
\end{tikzamatrix}
\]
\end{document}

and would produce:

tikz augmented matrix

Since that question isn't yet in a package, the code actually looks like this:

\documentclass{article}
%\url{https://tex.stackexchange.com/q/9492/86}
\usepackage{amsmath,tikz}
\usetikzlibrary{matrix,decorations}
\usepackage{calligraphy}
\usepackage{matrixcells}

\newlength\mtxrowsep
\setlength\mtxrowsep{1.5ex}
\newlength\mtxcolsep
\setlength\mtxcolsep{2\arraycolsep}

\makeatletter
\pgfdeclaredecoration{doubled lineto}{brace}
{
  \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
  {
    \pgfsyssoftpath@setcurrentpath{\pgfutil@empty}
    \pgfpathmoveto{\pgfpointorigin}
    \pgfpathlineto{\pgfqpoint{\pgfdecoratedremainingdistance}{0pt}}
    \pgfpathmoveto{\pgfqpoint{0pt}{\pgfdecorationsegmentamplitude}}
    \pgfpathlineto{\pgfqpoint{\pgfdecoratedremainingdistance}{\pgfdecorationsegmentamplitude}}
  }
  \state{final}{}%
}
\pgfdeclaredecoration{bracket}{brace}
{
  \state{brace}[width=+\pgfdecoratedremainingdistance,next state=final]
  {
    \pgfsyssoftpath@setcurrentpath{\pgfutil@empty}
    \pgfpathmoveto{\pgfpointorigin}
    \pgfpathlineto{\pgfqpoint{0pt}{\pgfdecorationsegmentamplitude}}
    \pgfpathlineto{\pgfqpoint{\pgfdecoratedremainingdistance}{\pgfdecorationsegmentamplitude}}
    \pgfpathlineto{\pgfqpoint{\pgfdecoratedremainingdistance}{0pt}}
  }
  \state{final}{}%
}
\makeatother

\expandafter\def\csname delimiter \string\lbrace\endcsname{calligraphic brace}
\expandafter\def\csname delimiter \string(\endcsname{calligraphic curved parenthesis}
\expandafter\def\csname delimiter \string|\endcsname{lineto}
\expandafter\def\csname delimiter \string\|\endcsname{doubled lineto}
\expandafter\def\csname delimiter \string[\endcsname{bracket}
\expandafter\def\csname delimiter \string\rbrace\endcsname{calligraphic brace}
\expandafter\def\csname delimiter \string)\endcsname{calligraphic curved parenthesis}
\expandafter\def\csname delimiter \string]\endcsname{bracket}

\tikzset{
  ams/.style={
    baseline=-.7ex,
    every delimiter/.style={yshift=-1pt},
    every left delimiter/.style={xshift=2pt},
    every right delimiter/.style={xshift=-2pt},
    every node/.style={inner sep=0pt},
    execute at end picture={
      \path (current bounding box.east) ++(\pgfkeysvalueof{/tikz/ams matrix xsep},0) (current bounding box.west) ++(-\pgfkeysvalueof{/tikz/ams matrix xsep},0);
    },
  },
  ams matrix xsep/.initial={.5ex},
  ams matrix/.style={
    inner sep=1pt,
    column sep=\mtxcolsep,
    row sep=\mtxrowsep,
%    ampersand replacement=\&,
    matrix of math nodes,
  },
  ams delimiters/.style args={#1,#2}{
    left delimiter={#1},
    right delimiter={#2},
  },
  delimiters/.style args={#1,#2}{
    \pgfkeysvalueof{/tikz/matrix delimiter type} delimiters={{#1},{#2}},
  },
  matrix delimiter type/.initial={tikz},
  tikz delimiter style/.style={
    thick,
  },
  tikz delimiters/.style args={#1,#2}{
    left tikz delimiter={#1},
    right tikz delimiter={#2},
  },
  left tikz delimiter/.style={
    render left tikz delimiter/.expand once={\csname delimiter \string#1\endcsname}
  },
  render left tikz delimiter/.style={
    append after command={(\tikzlastnode.north west) edge[tikz delimiter style,decorate,decoration={mirror,#1}] (\tikzlastnode.south west)}
  },
  right tikz delimiter/.style={
    render right tikz delimiter/.expand once={\csname delimiter \string#1\endcsname}
  },
  render right tikz delimiter/.style={
    append after command={(\tikzlastnode.north east) edge[tikz delimiter style,decorate,decoration={#1}] (\tikzlastnode.south east)}
  },
  bmatrix/.style={
    ams,
    every matrix/.style={
      ams matrix,
      delimiters={[,]},
    }
  },
  Bmatrix/.style={
    ams,
    every matrix/.style={
      ams matrix,
      delimiters={\lbrace,\rbrace},
    }
  },
  pmatrix/.style={
    ams,
    every matrix/.style={
      ams matrix,
      delimiters={(,)},
    }
  },
  vmatrix/.style={
    ams,
    every matrix/.style={
      ams matrix,
      delimiters={|,|},
    }
  },
  Vmatrix/.style={
    ams,
    every matrix/.style={
      ams matrix,
      delimiters={\|,\|},
    }
  },
}

\let\matamp=&

\catcode`\&=13
\makeatletter
\def&{\iftikz@is@matrix
  \pgfmatrixnextcell
  \else
  \matamp
  \fi}
\makeatother

%\usepackage{environ}
\def\endtikzmatrix{\\\egroup;\end{tikzpicture}}
\foreach \mtype in {b,B,p,v,V} {

\expandafter\xdef\csname tikz\mtype matrix\endcsname{%
    \noexpand\begin{tikzpicture}[\mtype matrix,matrix delimiter type={tikz}]
    \noexpand\matrix \noexpand\bgroup}
\expandafter\xdef\csname ams\mtype matrix\endcsname{%
    \noexpand\begin{tikzpicture}[\mtype matrix,matrix delimiter type={ams}]
    \noexpand\matrix \noexpand\bgroup}
\expandafter\global\expandafter\let\csname endtikz\mtype matrix\endcsname=\endtikzmatrix
\expandafter\global\expandafter\let\csname endams\mtype matrix\endcsname=\endtikzmatrix
}

\def\tikzamatrix{\begin{tikzpicture}[pmatrix,matrix delimiter type={tikz}]\matrix[label cells,name=am]\bgroup}
\def\endtikzamatrix{\\\egroup;\draw (am-cell-1-\the\pgfmatrixcurrentcolumn.north west) -- (am-cell-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn.south west);\end{tikzpicture}}

\begin{document}
\begin{tikzamatrix}
a & b & 0 \\
c & a + c & {\displaystyle \int_0^1 \sin(x) d x}
\end{tikzamatrix}
\end{document}

(The calligraphy and matrixcells package are available from TeX-SX launchpad page.)

1
  • Ah, once again, these are quite neat tools!
    – percusse
    Nov 28, 2011 at 14:21
1

Even if you ask for a TikZ solution, here is another way, with the nicematrix extension.

Thus, as pointed out by @Caramdir, lines are automatically adjusted, whatever you have in the matrix.

In addition you can use TikZ commands to tweak cells inside the matrix. Have a look at the documentation!

\documentclass{article}
\usepackage{nicematrix}
\DeclareRobustCommand{\dder}{\mathop{}\mathopen{}\mathrm{d}}
\begin{document}
  $\begin{pNiceArray}{c|c|c}
    1 & \int_{0}^{\infty}2x \dder x & 3 \\
    1 & 2 & 3 \\
    1 & 2+3+4 & 3 \\
    1 & 2 & 3 \\
  \end{pNiceArray}$
  
\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .