8

In the MWE below, I define a macro \markxy that draws dashed lines from a point to the x and y axes to indicate the x/y coordinates. Since I don't want the dashed lines to be drawn over my other "more important" lines, I collected the contents of \markxy within a scope and set it to be on the background layer.

I use the visible on key to create overlay effects. To save on typing, I group everything that is shown on frame 2 (including a \markxy path) within a scope and pass visible on=<2-> to that scope. However, the \markxy command doesn't seem to inherit the option from the scope.

I would like to understand why this is the case, and how to correct this. (My current solution is to copy the scope options and add them to \markxy. But this is not very efficient.)

MWE

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{intersections,backgrounds,scopes}
\tikzset{
  % use option [visible on=<+->] to uncover parts of a tikzpicture
  invisible/.style={opacity=0},
  visible on/.style={alt=#1{}{invisible}},
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
  },
}
\newcommand\axes[3][]{
  \draw[<->,#1](0,10)node[left]{$#3$}--(0,0)--(10,0)node[below]{$#2$};
}
\newcommand\markxy[4][]{
  \scoped[on background layer]
  \draw[dashed,#1](#2-|0,0)node[left]{$#3$}--(#2)--(#2|-0,0)node[below,anchor=base,yshift=-9pt]{$#4$};
}

\begin{document}
\begin{frame}
Frame \insertpagenumber\centering

\begin{tikzpicture}[font=\scriptsize,scale=.5]
  \draw[thick,name path=nd1](1,8)to[bend right=8](8,3)node[right]{$N^d$};
  \draw[thick,name path=ns1](5,1)to[bend right=8](9,6)node[above]{$N^s_1(r_1)$};
  \filldraw[name intersections={of=nd1 and ns1,by=ne1}](ne1)circle[radius=4pt];
  \markxy{ne1}{w_1}{N_1}
  \begin{scope}[visible on=<2->,orange]
    \draw[thick,name path=ns2,](1,3)to[bend right=8](5,8)node[above]{$N^s_2(r_1)$};
    \filldraw[name intersections={of=nd1 and ns2,by=ne2},](ne2)circle[radius=4pt];
    \markxy[]{ne2}{\widetilde w_2}{\widetilde N_2}
  \end{scope}
  \axes{N}{w}
\end{tikzpicture}
\end{frame}
\end{document}

Output (wrong) from MWE

enter image description here

Desired Output

enter image description here

  • Sorry but what is the difference between those two images exactly? – cfr Jul 25 '14 at 22:51
  • @cfr: In the first, the dashed lines leading to \widetilde w_2 and \widetilde N_2 and these two variables are shown on frame 1, and the lines are black. What I want instead, as is shown in the second image, is for the mentioned lines and variables to be shown only on frame 2. – Herr K. Jul 25 '14 at 22:55
  • Oh. I only see frame 2 and frame 2. I don't see a frame 1 anywhere. – cfr Jul 25 '14 at 22:56
  • 1
    The problem is the \scoped in the definition; if you comment out (or delete) he line \scoped[on background layer] in the definition of \markxy then you'll get the desired bahaviour. – Gonzalo Medina Jul 26 '14 at 1:02
  • 2
    To be a little more specific, the problem can be narrowed down to the [on background layer] specification for the \scoped; just suppressing this specification from the definition gives the desired result except, of course, for the layer specification. – Gonzalo Medina Jul 26 '14 at 1:23
6

The problem is not just for subscopes; simple scopes will also show the undesired behaviour. The problem is that you are wrongly using the visible on option (orange is also wrongly used) independently of the on background layer specification; the problem is solved as soon as visible on (and also orange) is passed as an option to the on background layer option.

The following simplified version of your code exhibits what I just mentioned; when using on background layer for a scope, additional options have to be passed as options to the on background layer option and not independently to the scope:

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{scopes,backgrounds}

\tikzset{
  % use option [visible on=<+->] to uncover parts of a tikzpicture
  invisible/.style={opacity=0},
  visible on/.style={alt=#1{}{invisible}},
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
  },
}

\makeatletter
\def\c@slideinframe{\beamer@slideinframe}
\def\beamerslideinframe{\beamer@slideinframe}
\makeatother

\begin{document}

\begin{frame}
\frametitle{Test slide \arabic{slideinframe}}

\begin{tikzpicture}[every node/.style={draw,circle}]
  \node at (0,0) {A};

  % wrong result
  \scoped[visible on=<2->,red,on background layer]
  \node at (1,0) {B};

  % right result
  \scoped[on background layer={red,visible on=<2->}]
  \node at (2,0) {C};
\end{tikzpicture}

\end{frame}
\end{document}

enter image description here

Notice that on slide one one has a wrong node "B" that is visible and black (just the label is red); this is so because visible on=<2-> and red were (wrongly) given as options to the \scoped. When passed as options to on background layer as for the node "C", everything work as expected.

This, in fact, is mentioned in the PGF manual (Section 43 Background Library, page 527):

/tikz/on background layer= options (no default)

This key can (only) be used with a {scope} or \scoped. It will cause everything inside the scope to be typeset on a background layer. The options will be executed inside background scope. This is useful since other options passed to the {scope} environment will be executed before the actual background material starts and, thus, will have no effect on it.

So, in order to have the visible on and orange options to be inherited, you will need to pass them as options to the on background layer key. Depending on the actual management of the argument for \markxy, you could, for example, define it as

\newcommand\markxy[4][]{
  \scoped[on background layer={#1}]
  \draw[dashed](#2-|0,0)node[left]{$#3$}--(#2)--(#2|-0,0)node[below,anchor=base,yshift=-9pt]{$#4$};
}

and then use it as

\markxy[visible on=<2->,orange]{ne2}{\widetilde w_2}{\widetilde N_2}

Your complete example with this ideas:

\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{intersections,backgrounds,scopes}
\tikzset{
  % use option [visible on=<+->] to uncover parts of a tikzpicture
  invisible/.style={opacity=0},
  visible on/.style={alt=#1{}{invisible}},
  alt/.code args={<#1>#2#3}{%
    \alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}} % \pgfkeysalso doesn't change the path
  },
}
\newcommand\axes[3][]{
  \draw[<->,#1](0,10)node[left]{$#3$}--(0,0)--(10,0)node[below]{$#2$};
}
\newcommand\markxy[4][]{
  \scoped[on background layer={#1}]
  \draw[dashed](#2-|0,0)node[left]{$#3$}--(#2)--(#2|-0,0)node[below,anchor=base,yshift=-9pt]{$#4$};
}

\begin{document}
\begin{frame}
Frame \insertpagenumber\centering

\begin{tikzpicture}[font=\scriptsize,scale=.5]
  \draw[thick,name path=nd1](1,8)to[bend right=8](8,3)node[right]{$N^d$};
  \draw[thick,name path=ns1](5,1)to[bend right=8](9,6)node[above]{$N^s_1(r_1)$};
  \filldraw[name intersections={of=nd1 and ns1,by=ne1}](ne1)circle[radius=4pt];
  \markxy{ne1}{w_1}{N_1}
  \begin{scope}[visible on=<2->,orange]
    \draw[thick,name path=ns2,](1,3)to[bend right=8](5,8)node[above]{$N^s_2(r_1)$};
    \filldraw[name intersections={of=nd1 and ns2,by=ne2},](ne2)circle[radius=4pt];
    \markxy[visible on=<2->,orange]{ne2}{\widetilde w_2}{\widetilde N_2}
  \end{scope}
  \axes{N}{w}
\end{tikzpicture}
\end{frame}
\end{document}

The result:

enter image description here

  • Thank you Gonzalo for the detailed answer. The example you gave at the end does generate the desired output. But it requires copying the scope options to \markxy, which I think is not very efficient. Anyhow, I did read the relevant sections in the manual, and it seems that there is no easy way to avoid such an inefficiency... Thank you all the same for the illuminating (as always) answer. – Herr K. Jul 27 '14 at 18:45

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.