[Tex/LaTex] tikz-cd: Shade faces of commutative cube

3dshadingtikz-cd

I would like to "shade" the faces of a commutative cube drawn using tikz-cd.

\documentclass{article}

\usepackage{tikz}
\usepackage{tikz-cd}

\begin{document}
\begin{tikzcd}
&
P
\ar{dl}[swap, sloped, near start]{t}
\ar{rr}{t'}
\ar[]{dd}[near end]{t}
& & R''
\ar{dd}{}
\ar{dl}[swap, sloped, near start]{}
\\
R
\ar[crossing over]{rr}[near start]{}
\ar{dd}[swap]{}
& & S''
\\
&
R'
\ar[near start]{rr}{}
\ar[sloped, near end]{dl}{}
& & S
\ar{dl}
\\
S'
\ar{rr}
& & P'
\ar[crossing over, leftarrow, near start]{uu}{}
\end{tikzcd}
\end{document}

enter image description here

One subtlety is that the vertices of this "cube" are not visible. However, there is a notional location for each vertex and I would like the shading to extend to that notional location. Really I'm just after a way of visually highlighting a face of the cube.

The shading should be quite transparent so that any edges of the cube that lie behind are still visible, and the arrows that lie along the edges of the shaded face are still clear.

Roughly speaking, I would like the effect of Drawing polyhedra using TikZ with semi-transparent and shading effect, but staying as much as possible within tikz-cd. I have a bunch of existing diagrams that I would like to animate by highlighting various faces in this way.

Is this possible, or would I need to rewrite my diagrams to use Tikz directly?

Best Answer

Yes, it's possible:

enter image description here

The code:

\documentclass{article}
\usepackage{tikz-cd}

\definecolor{cof}{RGB}{219,144,71}
\definecolor{pur}{RGB}{186,146,162}
\definecolor{greeo}{RGB}{91,173,69}
\definecolor{greet}{RGB}{52,111,72}

\begin{document}

\begin{tikzcd}[execute at end picture={
\foreach \Valor/\Nombre in   
{%
  tikz@f@1-2-1/a,tikz@f@1-1-2/b,tikz@f@1-1-4/c,tikz@f@1-2-3/d,%
  tikz@f@1-4-1/e,tikz@f@1-3-2/f,tikz@f@1-3-4/g,tikz@f@1-4-3/h%
}
{
\coordinate (\Nombre) at (\Valor);
}
\fill[pur,opacity=0.3] 
  (a) -- (b) -- (c) -- (d) -- cycle;
\fill[cof,opacity=0.3] 
  (a) -- (d) -- (h) -- (e) -- cycle;
\fill[greeo,opacity=0.3] 
  (h) -- (d) -- (c) -- (g) -- cycle;
  }
]
&
P
\ar{dl}[swap, sloped, near start]{t}
\ar{rr}{t'}
\ar[]{dd}[near end]{t}
& & R''
\ar{dd}{}
\ar{dl}[swap, sloped, near start]{}
\\
R
\ar[crossing over]{rr}[near start]{}
\ar{dd}[swap]{}
& & S''
\\
&
R'
\ar[near start]{rr}{}
\ar[sloped, near end]{dl}{}
& & S
\ar{dl}
\\
S'
\ar{rr}
& & P'
\ar[crossing over, leftarrow, near start]{uu}{}
\end{tikzcd}

\end{document}

The idea is to place a coordinate at each of the nodes in the diagram and then use those coordinates to do the filling; this is done using the execute at end picture key.

The internal numbering schema

Each node in a tikz-cd diagram has an internal name of the form

tikz@f@<number>-<row>-<column>

where <number> is the number of the tikz-cd diagram, <row> and <column> are the row and column, respectively, of the node. For example, the node labeled R in the above diagram (assuming it is the first tikz-cd diagram) would be

tikz@f@1-2-1

Had it been the 13th diagram, the internal name for R would've been

tikz@f@13-2-1

For example, the following shows, for each node, both its internal name and its new user-defined name. This is helpful if you want some guide during the filling process:

\documentclass{article}
\usepackage{tikz-cd}

\definecolor{cof}{RGB}{219,144,71}
\definecolor{pur}{RGB}{186,146,162}
\definecolor{greeo}{RGB}{91,173,69}
\definecolor{greet}{RGB}{52,111,72}

\begin{document}

\begin{tikzcd}[execute at end picture={
\foreach \Valor/\Nombre/\Posi in   
{%
  tikz@f@1-2-1/a/left,tikz@f@1-1-2/b/left,tikz@f@1-1-4/c/right,tikz@f@1-2-3/d/right,%
  tikz@f@1-4-1/e/left,tikz@f@1-3-2/f/left,tikz@f@1-3-4/g/right,tikz@f@1-4-3/h/right%
}
{
\coordinate (\Nombre) at (\Valor);
\node[\Posi=10pt,align=center] at (\Nombre) {\Valor\\ new name:\Nombre};
}
}
]
&
P
\ar{dl}[swap, sloped, near start]{t}
\ar{rr}{t'}
\ar[]{dd}[near end]{t}
& & R''
\ar{dd}{}
\ar{dl}[swap, sloped, near start]{}
\\
R
\ar[crossing over]{rr}[near start]{}
\ar{dd}[swap]{}
& & S''
\\
&
R'
\ar[near start]{rr}{}
\ar[sloped, near end]{dl}{}
& & S
\ar{dl}
\\
S'
\ar{rr}
& & P'
\ar[crossing over, leftarrow, near start]{uu}{}
\end{tikzcd}

\end{document}

enter image description here

If you don't want to keep finding the currect number of your diagram, you can use the associated internal count(er) \tikz@fig@count, but then something like

tikz@f@1-2-1

transforms into

tikz@f@\the\tikz@fig@count-2-1

and the resulting code is rather cumbersome:

\makeatletter
\begin{tikzcd}[
execute at end picture={
\foreach \Valor/\Nombre in   
{%
  tikz@f@\the\tikz@fig@count-2-1/a,tikz@f@\the\tikz@fig@count-1-2/b,tikz@f@\the\tikz@fig@count-1-4/c,tikz@f@\the\tikz@fig@count-2-3/d,%
  tikz@f@\the\tikz@fig@count-4-1/e,tikz@f@\the\tikz@fig@count-3-2/f,tikz@f@\the\tikz@fig@count-3-4/g,tikz@f@\the\tikz@fig@count-4-3/h%
}
{
\coordinate (\Nombre) at (\Valor);
}
\fill[cyan,opacity=0.15] 
  (a) -- (b) -- (c) -- (d) -- cycle;
\fill[orange,opacity=0.2] 
  (e) -- (f) -- (g) -- (h) -- cycle;
\fill[green,opacity=0.12] 
  (e) -- (a) -- (d) -- (h) -- cycle;
}
]
&
P
\ar{dl}[swap, sloped, near start]{t}
\ar{rr}{t'}
\ar[]{dd}[near end]{t}
& & R''
\ar{dd}{}
\ar{dl}[swap, sloped, near start]{}
\\
R
\ar[crossing over]{rr}[near start]{}
\ar{dd}[swap]{}
& & S''
\\
&
R'
\ar[near start]{rr}{}
\ar[sloped, near end]{dl}{}
& & S
\ar{dl}
\\
S'
\ar{rr}
& & P'
\ar[crossing over, leftarrow, near start]{uu}{}
\end{tikzcd}
\makeatother

A better approach

Using the alias key (and the standard |[...]| syntax for passing keys to nodes in a matrix), you can place easy-to-remember names to the nodes so you don't have to fiddle with the internal names and can use those simpler names for the shading:

\documentclass{article}
\usepackage{tikz-cd}

\definecolor{cof}{RGB}{219,144,71}
\definecolor{pur}{RGB}{186,146,162}
\definecolor{greeo}{RGB}{91,173,69}
\definecolor{greet}{RGB}{52,111,72}

\begin{document}

\begin{tikzcd}[execute at end picture={
\foreach \Nombre in  {A,B,...,H}
  {\coordinate (\Nombre) at (\Nombre.center);}
\fill[pur,opacity=0.3] 
  (A) -- (B) -- (C) -- (D) -- cycle;
\fill[greeo,opacity=0.3] 
  (A) -- (D) -- (H) -- (E) -- cycle;
\fill[cof,opacity=0.3] 
  (H) -- (D) -- (C) -- (G) -- cycle;
}]
&
|[alias=B]|P
\ar{dl}[swap, sloped, near start]{t}
\ar{rr}{t'}
\ar[]{dd}[near end]{t}
& & |[alias=C]|R''
\ar{dd}{}
\ar{dl}[swap, sloped, near start]{}
\\
|[alias=A]|R
\ar[crossing over]{rr}[near start]{}
\ar{dd}[swap]{}
& & |[alias=D]|S''
\\
&
|[alias=F]|R'
\ar[near start]{rr}{}
\ar[sloped, near end]{dl}{}
& & |[alias=G]|S
\ar{dl}
\\
|[alias=E]|S'
\ar{rr}
& & |[alias=H]|P'
\ar[crossing over, leftarrow, near start]{uu}{}
\end{tikzcd}

\end{document}

enter image description here

Use of backgrounds

For diagrams in which crossing over or description are not used, one can refine the answer doing the filling in a background layer; in this way, even with opacity=1 the filling doesn't affect labels nor arrows:

\documentclass{article}
\usepackage{tikz-cd}

\pgfdeclarelayer{background}
\pgfsetlayers{background,main}

\definecolor{cof}{RGB}{219,144,71}
\definecolor{pur}{RGB}{186,146,162}
\definecolor{greeo}{RGB}{91,173,69}
\definecolor{greet}{RGB}{52,111,72}

\begin{document}

\begin{tikzcd}[
execute at end picture={
  \begin{pgfonlayer}{background}
  \foreach \Nombre in  {A,B,...,E}
    {\coordinate (\Nombre) at (\Nombre.center);}
  \fill[pur!40] 
    (A) -- (B) -- (D) -- (C) -- cycle;
    \end{pgfonlayer}
}
]
  |[alias=A]|A
  \ar[rr,"f"]\ar[dd,"k"]\ar[dr,"\alpha"]
& & 
  |[alias=B]|B\ar[dd,"l",swap] 
\\
&
  |[alias=E]|E\ar[ur,"\beta"]\ar[dr,"\delta"] 
& 
\\
  |[alias=C]|C\ar[rr,"g"]\ar[ur,"\gamma"] 
& & 
  |[alias=D]|D 
\\
\end{tikzcd}

\end{document}

The result:

enter image description here

Related Question