4

Answering How to highlight portions of a matrix is a nice technique that isn't invasive, but requires manually numbering the nodes. I'd generalized it slightly:

\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}

This allows me to draw up to three boxes at a time (in matrices, or presumably in general equations), each time the Draw is executed the counters for the markers are incremented, and works nicely:

highlighted submatrices

(there are issues with the edge detection in Peter's method and I had to hack the hardcoded numbers slightly, which generates better but not perfect box boundaries)

Is there a way to have an array of counters instead of the set of three manually named counters that I have used? I'd like to be able to use the DrawNodeBox with a numeric index for a node counter array, instead of having wrapper methods for this function that explicitly pass the node names (that way I can use the optional parameters of DrawNodeBox directly).

i.e. I'd like an interface that could be used something like this:

\[
  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}

where \DrawNodeBox would increment an indexed counter for the node number as well as drawing the box, and \tikzmark would use the same indexed counter, using that counter to generate left and right node numbers automatically.

  • It would be easier if you would allow, say, \mytikzmark rather than tikzmark since then you could just use a wrapper rather than needing to patch or redefine the original macro. – cfr Nov 19 '14 at 15:58
  • I have no requirement to override the original macro. Having copy and pasted the tikzmark function from the linked answer, I didn't actually know that I was overriding anything. – Peeter Joot Nov 19 '14 at 16:10
  • You may want to have a look to Visually highlighting symbolic material in which I basically did what you are after for hf-tikz. – Claudio Fiandrino Nov 19 '14 at 17:16
2

I think this will do what you want and should also be less unwieldy than your current solution. The syntax is similar to that you requested except that different macro names are used on the grounds that it is not possible to simultaneously use the same command name for two different macros ;).

\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}

fancy matrix markup

EDIT

If you need more than 9 boxes per matrix (and you think your readers can cope!), you could use, for example:

\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}%
}

to disambiguate the coordinate names.

  • Can the node names have any delimeters between the concatenated numbers: #2\theMyBoxCounter. There's some cases where they could theoretically be ambiguous: 1 13 -> 113; 11 3 -> 113 (if you got really unlucky) – Peeter Joot Nov 20 '14 at 4:14
  • @PeeterJoot I thought you were dealing with at most 3 boxes? – cfr Nov 20 '14 at 15:04
  • That's all I've used in my current document. I was really just wondering. – Peeter Joot Nov 20 '14 at 19:21
  • @PeeterJoot I'd suggest trying hyphens if you need more than 9 boxes per matrix. (But I think 10 highlights per matrix would be rather confusing for your readers!) See my edit above. – cfr Nov 20 '14 at 21:18
  • I tried the hyphens you suggested, and the boxes all got positioned at the bottom. underscores also didn't work. I've just reverted to your original, which works fine for how I'm using it. – Peeter Joot Nov 21 '14 at 4:28
3

I realize this loses a lot of the nice default math matrix typesetting and requires some manual fiddling, but wouldn't something like the following be a bit (maybe not much) less unwieldy:

\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}

enter image description here

  • I'd like a solution that I can understand, or at least understand how to use, without having to care about the tex implementation details when I am writing the content. – Peeter Joot Nov 19 '14 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.