# TikZ: Execute code at end of scope OR picture and access its bounding box

TikZ provides the two keys execute at end picture={<code>} and execute at end scope={<code>} which can be used to execute any code at the end of the picture and of the current scope, respectively.

I now like to execute some code at the end of the picture if a TikZ key defined by me is used outside a scope environment, i.e. in the optional argument of tikzpicture or at the end of the scope if it is used inside the scope, i.e. in its optional argument. I also like to access the bounding box of that area, i.e. the complete one or only the one of the scope, respectively.

Is there am easy way to do this? Cascaded scopes should also be supported. I don't see a possibility to detect if I'm inside a scope or not. In theory the whole tikzpicture is a scope by itself and execute at end scope seems to work but the manual explicitly states it should only be used in the optional argument of a scope environment. I know about 'local bounding box' but then I would have to use it for every scope with a different name to avoid collisions.

-
I'd guess that without local bounding box, TikZ doesn't keep track of bounding boxes in scopes. The description of local bounding box says that “excessive use of this option (keeping track of dozens of bounding boxes at the same time) will slow things down”. So I think TikZ isn't doing that if not explicitly wanted. – Caramdir May 6 '11 at 20:07
Also, tikzpicture pretty much starts with \scope[every picture,#1] (passing the optional arguments from tikzpicture, see line 1300 of tikz.code.tex). Interestingly, code from execute at end of picture is executed before execute at end of scope. Possibly code executed at the end of the scope does not affect the baseline and trimming (at least a superficial reading of the code seems to indicate that). – Caramdir May 6 '11 at 20:14
@Caramdir: In my simple test the code of execute at end of picture was executed after execute at end of scope, at least the \node {A} in it was on top. – Martin Scharrer May 6 '11 at 20:16
@Martin: That is not what is happening for me (and is clearly not what is done in it v2.10 code). \begin{tikzpicture}[execute at end picture={\node[fill=red] {P};}, execute at end scope={\node[fill=green] {S};}] \draw (0,0) -- (1,0); \end{tikzpicture} gives a green square. – Caramdir May 6 '11 at 20:23
Sure. I just wanted to point out that testing whether you are in a scope could be rather difficult, because you are always in a scope. – Caramdir May 6 '11 at 20:36

Here is a partial solution to the problem of tracking local bounding boxes. Maybe you can make something out of that idea (be aware that this is not very well tested).

\documentclass{article}
\usepackage{tikz}

\makeatletter
\tikzset{every scope/.append style={
execute at begin scope={
% save the bounding box
\pgfpointanchor{current bounding box}{south west}
\pgfgetlastxy\tsx@outerbb@minx\tsx@outerbb@miny
\pgfpointanchor{current bounding box}{north east}
\pgfgetlastxy\tsx@outerbb@maxx\tsx@outerbb@maxy

% clear the bounding box
\pgfresetboundingbox
},
execute at end scope={
% do something useful with the scope bounding box
\draw (current bounding box.south west) rectangle (current bounding box.north east);

% reestablish the outer bounding box.
\expandafter\ifdim\tsx@outerbb@minx<16000pt
\path (\tsx@outerbb@minx, \tsx@outerbb@miny) rectangle (\tsx@outerbb@maxx,\tsx@outerbb@maxy);
\fi
}}
}
\makeatother

\begin{document}
\begin{tikzpicture}
\fill[red] (0,0) circle (2cm);
\begin{scope}[xshift=3cm,scale=0.8,blue]
\fill[blue] (0,0) circle (1cm);
\begin{scope}[green]
\fill (0,0.5) circle (0.3cm);
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}


This somewhat breaks whenever PGF stops tracking the bounding box (e.g. after a clip or transform canvas). To stop it from breaking horribly in these situations (and when there is an empty scope), one should at least disable the “draw current bounding box” whenever the current bounding box is too large.

It is also worth noting that any code that works with the scope bounding box has to be executed before the outer bounding box is reestablished. Unfortunately, I'm not aware of a version of execute at end scope that adds new code before the code that is already in the end scope hook. (Of course it wouldn't be hard to write such a key by permuting the code in the definition of execute at end scope.)

-
This seems to be a nice idea, but honestly not what I was looking for. If nothing else is coming up in the next two hours I will reward you the bounty before it is lost. – Martin Scharrer May 17 '11 at 11:23
Arg, now I waited to long. There should be really a warning 30 minute before or so, not just 24 hours. – Martin Scharrer May 17 '11 at 13:52
Not the full solution I was looking for, but I accept it now. There seems no better solution appearing here. Thanks for the effort! – Martin Scharrer Jun 30 '11 at 7:51