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.
4 Answers
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
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}
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);
Even better: set the minimum width property for the nodes in the matrix.
-
Like @xeroc's solution this fails when the entries are of different size.– CaramdirNov 27, 2011 at 20:32
-
-
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.– percusseNov 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.– CaramdirNov 27, 2011 at 23:00
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:
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.)
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}