回答如何突出显示矩阵的某些部分是一种很好的技术,它不是侵入性的,但需要手动对节点进行编号。我稍微概括了一下:
\documentclass{article}
\usepackage[svgnames]{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc}
%----------------------------------------------------------------------------------------
%
% https://tex.stackexchange.com/questions/40028/highlight-elements-in-the-matrix/40059#40059
%
% The following two macros allow marking left/upper, right/lower node positions for box drawing, and then drawing the box.
% unique node numbers must be passed to these.
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture] \node (#1) {};}
\newcommand{\DrawNodeBox}[3][]{%
\tikz[overlay,remember picture]{%
\draw[DarkOliveGreen,#1]%
($(#2)+(-0.4em,0.9em)$) rectangle%
($(#3)+(0.5em,-0.3em)$);}%
}
% here's some logic to allow for three boxes to be drawn with preceding marks, with counter increments after
% the boxes are drawn.
\newcounter{FirstBoxCounter}
\newcounter{SecondBoxCounter}
\newcounter{ThirdBoxCounter}
\newcommand{\tikzLeftMark}[0]{\tikzmark{tbFirstLeft\theFirstBoxCounter}}
\newcommand{\tikzLeftMarkSecond}[0]{\tikzmark{tbSecondLeft\theSecondBoxCounter}}
\newcommand{\tikzLeftMarkThird}[0]{\tikzmark{tbThirdLeft\theThirdBoxCounter}}
\newcommand{\tikzRightMark}[0]{\tikzmark{tbFirstRight\theFirstBoxCounter}}
\newcommand{\tikzRightMarkSecond}[0]{\tikzmark{tbSecondRight\theSecondBoxCounter}}
\newcommand{\tikzRightMarkThird}[0]{\tikzmark{tbThirdRight\theThirdBoxCounter}}
\newcommand{\DrawFirstBox}[0]{%
\DrawNodeBox[thick]{tbFirstLeft\theFirstBoxCounter}{tbFirstRight\theFirstBoxCounter}%
\stepcounter{FirstBoxCounter}%
}
\newcommand{\DrawSecondBox}[0]{%
\DrawNodeBox[thick]{tbSecondLeft\theSecondBoxCounter}{tbSecondRight\theSecondBoxCounter}%
\stepcounter{SecondBoxCounter}%
}
\newcommand{\DrawThirdBox}[0]{%
\DrawNodeBox[thick]{tbThirdLeft\theThirdBoxCounter}{tbThirdRight\theThirdBoxCounter}%
\stepcounter{ThirdBoxCounter}%
}
%------------------------------------------------------------------------------------------------------
\begin{document}
\[
M = \left[\begin{array}{*{13}{c}}
\tikzLeftMarkSecond{}0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 & 0\tikzRightMarkSecond{} & 1 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 0 & 1 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
\tikzLeftMark{}1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 \tikzRightMark{} & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 1 & 0 & \tikzLeftMarkThird{}0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 1 & 1 & 0 & 1 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\tikzRightMarkThird{} & 0 & 1 \\
\end{array}\right]
\]
\DrawFirstBox{}
\DrawSecondBox{}
\DrawThirdBox{}
\[
M = \left[\begin{array}{*{13}{c}}
0 & 0 & 0 & \tikzLeftMarkSecond{}-1 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 \\
0 & 0 & 0 & 0 & 1 & 0\tikzRightMarkSecond{} & 1 & 0 & 0 & 0 & 1 & 1 & 1 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
\tikzLeftMark{}-1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 \tikzRightMark{} & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 1 & 0 & \tikzLeftMarkThird{}0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\tikzRightMarkThird{} & 0 & 1 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0
\end{array}\right]
\]
\DrawFirstBox{}
\DrawSecondBox{}
\DrawThirdBox{}
\end{document}
这使我能够一次绘制最多三个框(在矩阵中,或者大概在一般方程中),每次执行绘制时,标记的计数器都会递增,并且运行良好:
(Peter 的方法中的边缘检测存在问题,我不得不稍微修改一下硬编码的数字,这样可以生成更好但不完美的框边界)
有没有办法拥有一个计数器数组,而不是我使用的一组三个手动命名的计数器?我希望能够使用带有节点计数器数组数字索引的 DrawNodeBox,而不是使用明确传递节点名称的此函数的包装器方法(这样我就可以直接使用 DrawNodeBox 的可选参数)。
即我想要一个可以使用如下方式的界面:
\[
M = \left[\begin{array}{*{13}{c}}
\tikzmark{left}{1}0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 & 0\tikzmark{right}{1} & 1 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 0 & 1 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
\tikzmark{left}{2}1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 \tikzmark{right}{2} & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 1 & 0 & \tikzmark{left}{3}0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 1 & 1 & 0 & 1 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\tikzmark{right}{3} & 0 & 1 \\
\end{array}\right]
\]
\DrawNodeBox[thick]{1}
\DrawNodeBox[thick]{2}
\DrawNodeBox[thick]{3}
\[
M = \left[\begin{array}{*{13}{c}}
0 & 0 & 0 & \tikzmark{left}{2}-1 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 \\
0 & 0 & 0 & 0 & 1 & 0\tikzmark{right}{2} & 1 & 0 & 0 & 0 & 1 & 1 & 1 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
\tikzmark{left}{3}-1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 \tikzmark{right}{3} & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 1 & 0 & \tikzmark{left}{1}0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\tikzmark{right}{1} & 0 & 1 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0
\end{array}\right]
\]
\DrawNodeBox[thick]{1}
\DrawNodeBox[thick]{2}
\DrawNodeBox[thick]{3}
其中 \DrawNodeBox 会增加节点号的索引计数器并绘制框,而 \tikzmark 将使用相同的索引计数器,并使用该计数器自动生成左节点号和右节点号。
答案1
我认为这可以满足您的要求,并且应该比您当前的解决方案更简洁。语法与您要求的语法类似,只是使用了不同的宏名,因为不可能同时对两个不同的宏使用相同的命令名 ;)。
\documentclass{article}
\usepackage[svgnames]{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc,tikzmark}
\newcommand{\DrawNodeBox}[3][]{%
\tikz[overlay,remember picture]{%
\draw[DarkOliveGreen,#1]%
($({pic cs:#2})+(-0.4em,0.9em)$) rectangle%
($({pic cs:#3})+(0.5em,-0.3em)$);}%
}
\newcounter{MyBoxCounter}
\setcounter{MyBoxCounter}{0}
\gdef\MyStepBoxCounter{\stepcounter{MyBoxCounter}}
\newcommand\DrawMyBox[2][]{%
\DrawNodeBox[#1]{tbleft#2\theMyBoxCounter}{tbright#2\theMyBoxCounter}%
\gdef\MyStepBoxCounter{\stepcounter{MyBoxCounter}}%
}
\newcommand\mytikzmark[2]{%
\MyStepBoxCounter%
\global\let\MyStepBoxCounter\relax%
\tikzmark{tb#1#2\theMyBoxCounter}%
}
\begin{document}
\[
M = \left[\begin{array}{*{13}{c}}
\mytikzmark{left}{1}0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 & 0\mytikzmark{right}{1} & 1 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 0 & 1 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
\mytikzmark{left}{2}1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 1 \mytikzmark{right}{2} & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 1 & 0 & \mytikzmark{left}{3}0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 1 & 1 & 0 & 1 & 0 & 0 & 1 & 1 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\mytikzmark{right}{3} & 0 & 1 \\
\end{array}\right]
\]
\DrawMyBox[thick, blue]{1}
\DrawMyBox[thick, red]{2}
\DrawMyBox[thick, green]{3}
\[
M = \left[\begin{array}{*{13}{c}}
0 & 0 & 0 & \mytikzmark{left}{2}-1 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 \\
0 & 0 & 0 & 0 & 1 & 0\mytikzmark{right}{2} & 1 & 0 & 0 & 0 & 1 & 1 & 1 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
\mytikzmark{left}{3}-1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\
0 \mytikzmark{right}{3} & 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 \\
0 & 0 & 0 & 0 & 1 & 0 & \mytikzmark{left}{1}0 & 0 & 0 & 0 & 0 & 1 & 0 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0\mytikzmark{right}{1} & 0 & 1 \\
0 & 0 & 1 & 0 & 0 & 0 & 0 & 1 & 0 & 0 & 1 & 0 & 0
\end{array}\right]
\]
\DrawMyBox[thick, magenta]{1}
\DrawMyBox[thick, orange]{2}
\DrawMyBox[thick, cyan]{3}
\end{document}
编辑
如果每个矩阵需要超过 9 个框(并且您认为读者可以应付!),您可以使用,例如:
\newcommand\DrawMyBox[2][]{%
\DrawNodeBox[#1]{tbleft-#2-\theMyBoxCounter}{tbright-#2-\theMyBoxCounter}%
\gdef\MyStepBoxCounter{\stepcounter{MyBoxCounter}}%
}
\newcommand\mytikzmark[2]{%
\MyStepBoxCounter%
\global\let\MyStepBoxCounter\relax%
\tikzmark{tb#1-#2-\theMyBoxCounter}%
}
消除坐标名称的歧义。
答案2
我意识到这会失去很多好的默认数学矩阵排版,并且需要一些手动操作,但像下面这样的东西不会有点(可能不会太多)不那么笨重:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fit}
\begin{document}
\[
M=\left[\;
\begin{tikzpicture}[baseline=(0:0), y=\baselineskip,x=2em]
\foreach \row [count=\i] in {%
{ 0, 1, 0, 0, 0, 0},
{ 0, 1, 0, 1, 0, 0},
{ 0, 0, 1,-1, 0, 0},
{ 1, 1, 0, 0, 0, 0},
{ 0, 1, 1, 0, 0, 0},
{ 0, 0, 0, 0,-1, 0}}
\foreach \col [count=\j] in \row
\node [inner ysep=0pt, inner xsep=2pt]
(m-\i-\j) at (\j,-\i+3.666) {\ensuremath{\col}};
\node [fit=(m-1-1) (m-2-3), draw, thick]{};
\node [fit=(m-3-5) (m-6-6), draw, thick]{};
\end{tikzpicture}
\;\right]
\]
\end{document}