# Why opacity changes in a scope are not applied to the background layer?

I have some complex schematics that I want to uncover by parts is a presentation.

The schematic is in a external file that I do not want to modify and to do that, I use tags that are styles that may or not be defined. If undefined they turn to the empty style. Otherwise, they can change opacity (or whatever). As usual, these styles can be applied to either a path or a scope.

This worked very well until I added some part of drawing in the background to improve the picture (see answer to How to define a style that will draw some lines on the background layer?).

Now it happens that

• opacity changes are always properly applied to the foreground layer

• they are correctly applied to the background layer if used in the path style \draw[..., opacity=0.5] ...

• they are not applied to the background layer within a scope \begin{scope}[opacity=0.5]...\end{scope} (but opacity changes are properly applied in the foreground)

Here is a mwe illustrating what I want to do and showing the problem

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{backgrounds}

% to put something on the background
\tikzset{%
on layer/.code={
\pgfonlayer{#1}\begingroup
\aftergroup\endpgfonlayer
\aftergroup\endgroup
}
}

% to process undefined tags
\pgfkeys{/tag/.is family, /tag,
.unknown/.code = {
\pgfkeyssetvalue{\pgfkeyscurrentpath/\pgfkeyscurrentname}{}
}
}

% opacity changing styles
\pgfkeys{
/tikz/greyed/.style={opacity=0.4},
/tikz/hidden/.style={opacity=0},
}

% drawned of bg layer
\tikzset{
wire/.style={
thick,
red,
on layer=background},
}

\begin{document}
\centering

Inital picture\\
\begin{tikzpicture}[]
\node[draw, blue, /tag/A] (A) at (0,0) {A} ;
\draw[wire,/tag/A] (-1,0) -- (A) ;
\node[draw, blue, /tag/B] (B) at (2,0) {B} ;
\draw[wire,/tag/B] (A) -- (B) ;
\node[draw, blue, /tag/C] (C) at (4,0) {C} ;
\draw[wire,/tag/C] (B) -- (C) ;
\draw[wire,/tag/C] (C) -- ++(1,0) ;
\end{tikzpicture}
\bigskip

Picture with element opacity modified in the element style\\
All is properly processed\\
\begin{tikzpicture}[
/tag/B/.style={greyed},
/tag/C/.style={hidden},
]
\node[draw, blue, /tag/A] (A) at (0,0) {A} ;
\draw[wire,/tag/A] (-1,0) -- (A) ;
\node[draw, blue, /tag/B] (B) at (2,0) {B} ;
\draw[wire,/tag/B] (A) -- (B) ;
\node[draw, blue, /tag/C] (C) at (4,0) {C} ;
\draw[wire,/tag/C] (B) -- (C) ;
\draw[wire,/tag/C] (C) -- ++(1,0) ;
\end{tikzpicture}
\bigskip

Picture with element opacity modified in scope style\\
Nodes in foreground are modified, but wires in bg are not\\
\begin{tikzpicture}[
/tag/B/.style={greyed},
/tag/C/.style={hidden},
]
\begin{scope}[/tag/A]
\node[draw, blue] (A) at (0,0) {A} ;
\draw[wire] (-1,0) -- (A) ;
\end{scope}
\begin{scope}[/tag/B]
\node[draw, blue] (B) at (2,0) {B} ;
\draw[wire] (A) -- (B) ;
\end{scope}
\begin{scope}[/tag/C]
\node[draw, blue] (C) at (4,0) {C} ;
\draw[wire] (B) -- (C) ;
\draw[wire] (C) -- ++(1,0) ;
\end{scope}
\end{tikzpicture}

\end{document}


Is there a workaround to apply opacity changes to the bg layer in a scope?

• AFAICT, tikz does not save the opacity, but rather uses the pdf driver to implement the opacity immediately, which means that everything drawn after should use the same opacity. So the background layer must be drawn first (which is certainly the easiest way to implement layers). – John Kormylo Jul 22 '19 at 12:03

You could store the opacity and set it explicitly in your wire style:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{backgrounds}

% to put something on the background
\tikzset{%
on layer/.code={
\pgfonlayer{#1}\begingroup
\aftergroup\endpgfonlayer
\aftergroup\endgroup
}
}

% to process undefined tags
\pgfkeys{/tag/.is family, /tag,
.unknown/.code = {
\pgfkeyssetvalue{\pgfkeyscurrentpath/\pgfkeyscurrentname}{}
}
}

\pgfkeys{/tikz/storeopacity/.store in=\currentopacity, /tikz/storeopacity=1}
% opacity changing styles
\pgfkeys{
/tikz/greyed/.style={opacity=0.4,storeopacity=0.4},
/tikz/hidden/.style={opacity=0,storeopacity=0},
}

% drawned of bg layer
\tikzset{
wire/.style={
thick,
red,
opacity=\currentopacity,
on layer=background},
}

\begin{document}
\centering

Inital picture\\
\begin{tikzpicture}[]

\node[draw, blue, /tag/A] (A) at (0,0) {A} ;
\draw[wire,/tag/A] (-1,0) -- (A) ;
\node[draw, blue, /tag/B] (B) at (2,0) {B} ;
\draw[wire,/tag/B] (A) -- (B) ;
\node[draw, blue, /tag/C] (C) at (4,0) {C} ;
\draw[wire,/tag/C] (B) -- (C) ;
\draw[wire,/tag/C] (C) -- ++(1,0) ;
\end{tikzpicture}
\bigskip

Picture with element opacity modified in the element style\\
All is properly processed\\
\begin{tikzpicture}[
/tag/B/.style={greyed},
/tag/C/.style={hidden},
]
\node[draw, blue, /tag/A] (A) at (0,0) {A} ;
\draw[wire,/tag/A] (-1,0) -- (A) ;
\node[draw, blue, /tag/B] (B) at (2,0) {B} ;
\draw[wire,/tag/B] (A) -- (B) ;
\node[draw, blue, /tag/C] (C) at (4,0) {C} ;
\draw[wire,/tag/C] (B) -- (C) ;
\draw[wire,/tag/C] (C) -- ++(1,0) ;
\end{tikzpicture}
\bigskip

Picture with element opacity modified in scope style\\
Nodes in foreground are modified, but wires in bg are not\\
\begin{tikzpicture}[
/tag/B/.style={greyed},
/tag/C/.style={hidden},
]
\begin{scope}[/tag/A]
\node[draw, blue] (A) at (0,0) {A} ;
\draw[wire] (-1,0) -- (A) ;
\end{scope}
\begin{scope}[/tag/B]
\node[draw, blue] (B) at (2,0) {B} ;
\draw[wire] (A) -- (B) ;
\end{scope}
\begin{scope}[/tag/C]
\node[draw, blue] (C) at (4,0) {C} ;
\draw[wire] (B) -- (C) ;
\draw[wire] (C) -- ++(1,0) ;
\end{scope}
\end{tikzpicture}

\end{document}