# Fitting as a background to nodes in multiple pictures

I'm using TikZ pictures to represent terms in an equation, and I want to visually group some of these terms by drawing a rectangle behind them. But each term is its own separate picture, which means I can't just draw the rectangle on a background layer. Is there some way I can make the rectangle appear behind the equation, despite not knowing where to draw the rectangle in advance?

The following example demonstrates the best I can do on my own, namely having the rectangle appear in front of the equation. I've edited the example from the previous version of the question to make it more realistic, because it affects the usability of some of the suggested solutions. (Sorry! My MWE was too minimal at first.)

Code:

\documentclass[b3paper]{baposter}
\usepackage{tikz,amsmath}
\usetikzlibrary{fit}

\begin{document}
\begin{poster}{bgColorOne=blue!20!white,background=plain}{}{}{}{}
\begin{align}
x &=
\begin{tikzpicture}[remember picture]
\node[circle,fill=red,minimum width=1cm] {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=cyan,minimum width=1cm] (first node) {};
\end{tikzpicture}
\\
y &=
\begin{tikzpicture}[remember picture]
\node[circle,fill=red,minimum width=1cm] {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=cyan,minimum width=1cm] (second node) {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=green,minimum width=1cm] (third node) {};
\end{tikzpicture}
\end{align}

\begin{tikzpicture}[remember picture,overlay]
\node[draw=red,fill=yellow,fill opacity=0.8,fit=(first node) (second node) (third node),rectangle] {};
\end{tikzpicture}
\end{posterbox}
\end{poster}
\end{document}


It's a little tricky because

1. the pictures I want to highlight are not contiguous in the source, and
2. there is an existing background which I have to draw over, so it's really a matter of sticking a picture between two existing "layers" of the document.
-
You could also try adding the option baseline=-1ex to your first two tikzpictures to get nicer baseline alignment. –  benwilfut Mar 18 '13 at 13:29
@benwilfut yeah, I do that in the actual document, but I figured I'd omit it here in the interest of making the MWE minimal. –  David Z Mar 18 '13 at 13:58
That's very commendable! –  benwilfut Mar 18 '13 at 14:04

One possibility is to use Andrew Stacey's improved version of \tikzmark (See his answer to tikzmark to have different behaviour if first run (and mark locations not yet available)); in the following example, the \placemark command is in charge of, well... placing the marks; its first mandatory argument can be used to select an anchor of the current bounding box, and the second argument gives the mark a name. The names can then be used as arguments for the \DrawRect macro:

\documentclass{article}
\usepackage{amsmath}
\usepackage{tikz}
\usetikzlibrary{fit}

\makeatletter
\tikzset{%
remember picture with id/.style={%
remember picture,
overlay,
save picture id=#1,
},
save picture id/.code={%
\edef\pgf@temp{#1}%
\immediate\write\pgfutil@auxout{%
\noexpand\savepointas{\pgf@temp}{\pgfpictureid}}%
},
if picture id/.code args={#1#2#3}{%
\@ifundefined{save@pt@#1}{%
\pgfkeysalso{#3}%
}{
\pgfkeysalso{#2}%
}
}
}

\def\savepointas#1#2{%
\expandafter\gdef\csname save@pt@#1\endcsname{#2}%
}

\def\tmk@labeldef#1,#2\@nil{%
\def\tmk@label{#1}%
\def\tmk@def{#2}%
}

\tikzdeclarecoordinatesystem{pic}{%
\pgfutil@in@,{#1}%
\ifpgfutil@in@%
\tmk@labeldef#1\@nil
\else
\tmk@labeldef#1,(0pt,0pt)\@nil
\fi
\@ifundefined{save@pt@\tmk@label}{%
\tikz@scan@one@point\pgfutil@firstofone\tmk@def
}{%
\pgfsys@getposition{\csname save@pt@\tmk@label\endcsname}\save@orig@pic%
\pgfsys@getposition{\pgfpictureid}\save@this@pic%
\pgf@process{\pgfpointorigin\save@this@pic}%
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgfpointorigin\save@orig@pic}%
}%
}
\newcommand\tikzmark[2][]{%
\tikz[remember picture with id=#2] #1;}
\makeatother

\newcommand\placemark[2]{%
\node[inner sep=0pt,outer sep=0pt] at #1 {\tikzmark{#2}};
}

\newcommand\DrawRect[2]{%
\begin{tikzpicture}[overlay,remember picture]%
\node[draw=red,fill=yellow,fill opacity=0.8,fit=(pic cs:#1) (pic cs:#2),rectangle] {};
\end{tikzpicture}%
}

\begin{document}

\DrawRect{fnode}{snode}
\DrawRect{finode}{sinode}
\DrawRect{fiinode}{siinode}

$$x = \begin{tikzpicture}[remember picture] \node[circle,fill=red,minimum width=1cm] (first node) {}; \end{tikzpicture} + \begin{tikzpicture}[remember picture] \node[circle,fill=cyan,minimum width=1cm] (first node) {}; \placemark{(current bounding box.north west)}{fnode} \end{tikzpicture} + \begin{tikzpicture}[remember picture] \node[circle,fill=green,minimum width=1cm] (second node) {}; \placemark{(current bounding box.south east)}{snode} \end{tikzpicture}$$

$$x = \begin{tikzpicture}[remember picture] \node[circle,fill=red,minimum width=1cm] (first node) {}; \placemark{(current bounding box.north west)}{finode} \end{tikzpicture} + \begin{tikzpicture}[remember picture] \node[circle,fill=cyan,minimum width=1cm] (first node) {}; \placemark{(current bounding box.south east)}{sinode} \end{tikzpicture} + \begin{tikzpicture}[remember picture] \node[circle,fill=green,minimum width=1cm] (second node) {}; \end{tikzpicture}$$

\begin{align}
x &=
\begin{tikzpicture}[remember picture]
\node[circle,fill=red,minimum width=1cm] {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=cyan,minimum width=1cm] (first node) {};
\placemark{(current bounding box.north west)}{fiinode}
\end{tikzpicture}
\\
y &=
\begin{tikzpicture}[remember picture]
\node[circle,fill=red,minimum width=1cm] {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=cyan,minimum width=1cm] (second node) {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=green,minimum width=1cm] (third node) {};
\placemark{(current bounding box.south east)}{siinode}
\end{tikzpicture}
\end{align}

\end{document}


The code needs to be run three times.

-

There may be a more elegant 'pure TikZ' solution, but you could push your rectangle to the background using the atbegshi package:

\documentclass{article}
\usepackage{atbegshi}
\usepackage{tikz}
\usetikzlibrary{fit}

\begin{document}
$$x = \begin{tikzpicture}[remember picture] \node[circle,fill=cyan,minimum width=1cm] (first node) {}; \end{tikzpicture} + \begin{tikzpicture}[remember picture] \node[circle,fill=green,minimum width=1cm] (second node) {}; \end{tikzpicture}$$

\AtBeginShipoutNext{
\AtBeginShipoutUpperLeft{
\begin{tikzpicture}[remember picture,overlay]
\node[draw=red,fill=yellow,fill opacity=0.8,fit=(first node) (second node),rectangle] {};
\end{tikzpicture}
}
}
\end{document}

-
That works for what I originally wrote, though you made me realize there's an existing background that I have to draw over, so I'm not sure this really works for my purposes. But I'm upvoting anyway, since you did answer the question as I posed it at first :-) –  David Z Mar 18 '13 at 14:31

You can always use hf-tikz (thus two compilation runs are necessary):

\documentclass[b3paper]{baposter}
\usepackage{amsmath}
\usepackage[customcolors,norndcorners]{hf-tikz}
\tikzset{hf color setting/.style={
set fill color=yellow,
set border color=red,
},
hf specifications no vert align/.style={
above left offset={-0.05cm,1.05cm},
below right offset={0.05cm,-0.1cm},
hf color setting,
},
}

\begin{document}
\begin{poster}{bgColorOne=blue!20!white,background=plain}{}{}{}{}
\begin{align}
x &=
\begin{tikzpicture}[remember picture]
\node[circle,fill=red,minimum width=1cm] {};
\end{tikzpicture}
+
\tikzmarkin[hf specifications no vert align]{a}
\begin{tikzpicture}[remember picture]
\node[circle,fill=cyan,minimum width=1cm] (first node) {};
\end{tikzpicture}
\\
y &=
\begin{tikzpicture}[remember picture]
\node[circle,fill=red,minimum width=1cm] {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=cyan,minimum width=1cm] (second node) {};
\end{tikzpicture}
+
\begin{tikzpicture}[remember picture]
\node[circle,fill=green,minimum width=1cm] (third node) {};
\end{tikzpicture}
\tikzmarkend{a}
\end{align}
\end{posterbox}
\end{poster}
\end{document}


The result:

Of course this needs baposter.cls to be compiled.

First version

\documentclass{article}
\usepackage[customcolors,norndcorners]{hf-tikz}
\tikzset{hf color setting/.style={
set fill color=yellow,
set border color=red,
},
hf specifications vert align/.style={
above left offset={-0.05cm,0.75cm},
below right offset={0.05cm,-0.55cm},
hf color setting,
},
hf specifications no vert align/.style={
above left offset={-0.05cm,1.05cm},
below right offset={0.05cm,-0.1cm},
hf color setting,
},
}

% vertical alignment within math environments see:
% http://tex.stackexchange.com/questions/59658/use-of-tikzpicture-matrix-in-align-or-gather-environment/59660#comment126261_59660
\def\vertmathalign{-\the\dimexpr\fontdimen22\textfont2\relax}
\begin{document}
With circle vertical alignment:
x = \begin{tikzpicture}[baseline=\vertmathalign,remember picture] \node[circle,fill=red,minimum width=1cm] (first node) {}; \end{tikzpicture} + \tikzmarkin[hf specifications vert align]{a} \begin{tikzpicture}[baseline=\vertmathalign,remember picture] \node[circle,fill=cyan,minimum width=1cm] (first node) {}; \end{tikzpicture} + \begin{tikzpicture}[baseline=\vertmathalign,remember picture] \node[circle,fill=green,minimum width=1cm] (second node) {}; \end{tikzpicture} \tikzmarkend{a}
Without
x = \begin{tikzpicture}[remember picture] \node[circle,fill=red,minimum width=1cm] (first node) {}; \end{tikzpicture} + \tikzmarkin[hf specifications no vert align]{b} \begin{tikzpicture}[remember picture] \node[circle,fill=cyan,minimum width=1cm] (first node) {}; \end{tikzpicture} + \begin{tikzpicture}[remember picture] \node[circle,fill=green,minimum width=1cm] (second node) {}; \end{tikzpicture} \tikzmarkend{b}
\end{document}


I've distinguished between the case in which circles are correctly aligned with the formula and not; the result is:

-