% Note the LaTeX code here uses a package that both shows the code and the output.
% This package is: tkzexample
% This ensures that the LaTeX corresponds to the figure.
%
% However, this means that there are extra lines in the source code below:
%
% \begin{tkzexample}
% [....]
% \end{tkzexample}
%
% (This should not cause confusion since the lines do not show up in the
% pdf version, but we note it here, in case a reader does not have access to the pdf)
\documentclass[11pt]{article}
\usepackage{natbib}
\usepackage{amsmath,amssymb,booktabs,url}
\usepackage{xcolor}
\usepackage{pgf,tikz}
\usetikzlibrary{arrows,shapes.arrows,shapes.geometric,
shapes.multipart,decorations.pathmorphing,positioning,
swigs}
\usepackage{tkzexample} % to show code and pictures side by side
%%% Note useful tkzexample options here:
%% [very small] makes the code small
%% [vbox] stacks the figure before the code
\begin{document}
\colorlet{graphicbackground}{blue!10!white}%
\colorlet{codebackground}{red!10}%
\colorlet{codeonlybackground}{red!10}% sets background for tkzltxexample
\title{TikZ/PGF shape library for constructing Single-World Intervention Graphs (SWIGs)}
\author{Thomas S. Richardson\\[2pt]
Department of Statistics\\
University of Washington}
\date{9 July 2021}
\maketitle
Single World Intervention Graphs (SWIGs) are a graphical formalism for unifying two approaches to building
(statistical) causal models \citep{swigs}.
Key to the representation is an operation of `node splitting', whereby a single node is divided into
two pieces. It is important that the resulting halves can still be seen to have originated from a single node.
\begin{center}
\begin{tikzpicture}
\tikzset{line width=1.5pt}
\node[name=a1,shape=swig hsplit, swig hsplit={line color lower=red}]{
\nodepart{upper}{$A_1$}
\nodepart{lower}{$a_1$} };
\node[name=a2,shape=swig vsplit, right=of a1, swig vsplit={line color right=red}]{
\nodepart{left}{$A_2(a_1)$}
\nodepart{right}{$a_2$} };
\draw[->,line width=1pt](a1) to[out=350,in=180] (a2);
\end{tikzpicture}
\end{center}
It has been hard to draw SWIGs using standard packages in TikZ/PGF. Two separate {\tt semicircle} shapes can be used, but it is difficult to ensure that the two halves look as if they arise from a single circle, at least without introducing a lot of whitespace. TikZ does contain a shape, called {\tt split ellipse}, but this does not provide a way to add space between the two halves of the shape.
(There does not appear to be a semi-ellipse shape.)
We address this by introducing two multipart shapes: {\tt swig hsplit} that creates an ellipse that has been split horizontally, and
and {\tt swig vsplit} that is split vertically. The latter shape also adjusts the ratio of the two halves depending on the text that is contained.
\eject
\subsection*{Preliminaries}
The examples included below use the following packages:
%%%%%
\begin{tkzltxexample}[]
\documentclass[10pt]{article}
\usepackage{amsmath,amssymb,xcolor}
\usepackage{pgf,tikz}
\usetikzlibrary{arrows,shapes.arrows,shapes.geometric,
shapes.multipart,decorations.pathmorphing,positioning,
swigs}
\begin{document}
..
\end{tkzltxexample}
%%%%%
%\noindent The last library listed here uses the code in the file:\par
%{\tt tikzlibraryshapes.swigs.code.tex} \par
%\noindent (As this is not part of the TeX distribution, this file should be placed in the working directory.)
\subsection*{SWIG with horizontal split}
Here is a very simple example:
\begin{tkzexample}[very small,latex=4cm]
\begin{tikzpicture}
\node[name=a1,shape=swig hsplit]{
\nodepart{upper}{$A_1$}
\nodepart{lower}{$a_1$} };
\node[name=a2,shape=swig hsplit,right=of a1]{
\nodepart{upper}{$A_2(a_1)$}
\nodepart{lower}{$a_2$} };
\draw[->](a1) to[out=350,in=170] (a2);
\end{tikzpicture}
\end{tkzexample}
\bigskip
\noindent The parameter {\tt gap} can be adjusted to change the size of the gap:
\begin{tkzexample}[latex=4cm, very small]
\begin{tikzpicture}
\node[name=a1,shape=swig hsplit,
swig hsplit={gap=5pt}]{
\nodepart{upper}{$A_1$}
\nodepart{lower}{$a_1$} };
\node[name=a2,shape=swig hsplit, right=of a1]{
\nodepart{upper}{$A_2(a_1)$}
\nodepart{lower}{$a_2$} };
\draw[->](a1) to[out=350,in=170] (a2);
\end{tikzpicture}
\end{tkzexample}
\medskip
\eject
\noindent This can also be done globally for all split nodes;
here we also make the line color red for lower halves.
\begin{tkzexample}[latex=4cm, very small]
\begin{tikzpicture}
\tikzset{swig hsplit={gap=5pt,line color lower=red}}
\node[name=a1,shape=swig hsplit]{
\nodepart{upper}{$A_1$}
\nodepart{lower}{$a_1$} };
\node[name=a2,shape=swig hsplit, right=of a1]{
\nodepart{upper}{$A_2(a_1)$}
\nodepart{lower}{$a_2$} };
\draw[->](a1) to[out=350,in=170] (a2);
\end{tikzpicture}
\end{tkzexample}
\medskip
\noindent For black and white publications color may not be sufficient to distinguish
upper and lower halves. For this purpose a double line can be used.
{\tt inner line width lower} specifies the width of the inner gap.
\begin{tkzexample}[latex=4cm, very small]
\begin{tikzpicture}
\tikzset{line width=1.5pt,
swig hsplit={gap=4pt,
inner line width lower=0.5pt}}]
\node[name=a1,shape=swig hsplit]{
\nodepart{upper}{$A_1$}
\nodepart{lower}{$a_1$} };
\node[name=a2,shape=swig hsplit, right=of a1]{
\nodepart{upper}{$A_2(a_1)$}
\nodepart{lower}{$a_2$} };
\draw[->,line width=1.5pt,>=stealth](a1)
to[out=350,in=170] (a2);
\end{tikzpicture}
\end{tkzexample}
\eject
\noindent The example below shows the full set of anchors and other options.
\begin{center}
\begin{tkzexample}[vbox, very small]
\Huge
\begin{tikzpicture}
\pgfsetinnerstrokecolor{blue!10!white} % so inner line col=background
\tikzset{shape example/.style={fill=yellow!5,
inner sep=0.3cm,outer sep=0cm}}
\node[name=s, shape example, shape=swig hsplit,
swig hsplit={
line color upper=red!30,
fill color upper=yellow!30,
line color lower=green!30,
fill color lower=yellow!30,
gap=40pt,
line width upper= 10pt,
inner line width upper = 0pt,
line width lower=15pt,
inner line width lower = 4pt}]
{\nodepart[red!30]{upper}{$A_4(a_1,a_2)$}
\nodepart[green!30]{lower}{$a_4$}};
\draw[->,line width=5pt, draw=blue!15,>=stealth]
(s.upper center) to (s.lower center);
\foreach \anchor/\placement in
{center/right, upper center/left,
upper/below, lower center/left, lower/left,
60/above right, 200/below left,
mid/above, mid east/above right, mid west/above left,
upper base/below right, base east/right, base west/left,
upper east/right, upper west/left,
north/above, south/below, west/left, east/right,
lower west/left, lower east/right,
north east/above right, south east/below right,
south west/below left, north west/above left,
lower base/below right, lower mid/above}
\draw[shift=(s.\anchor)] plot[mark=x] coordinates{(0,0)}
node[\placement] {\scriptsize\texttt{(s.\anchor)}};
\end{tikzpicture}
\end{tkzexample}
\end{center}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\eject
\subsection*{SWIG with vertical split}
Here we describe the instructions for creating ellipses with vertical splits. These are often more efficient in terms of space.
As before, first a very simple example:
\begin{tkzexample}[very small,latex=5.5cm]
\begin{tikzpicture}
\node[name=a1,shape=swig vsplit]{
\nodepart{left}{$A_1$}
\nodepart{right}{$a_1$} };
\node[name=a2, right=5mm of a1,
shape=swig vsplit] {
\nodepart{left}{$A_2(a_1)$}
\nodepart{right}{$a_2$} };
\draw[->](a1) to (a2);
\end{tikzpicture}
\end{tkzexample}
\bigskip
\noindent The parameter {\tt gap} can be adjusted to change the size of the gap:
\begin{tkzexample}[very small,latex=5cm]
\begin{tikzpicture}
\node[name=a1,shape=swig vsplit,
swig vsplit={gap=3pt}]{
\nodepart{left}{$A_1$}
\nodepart{right}{$a_1$} };
\node[name=a2, right=3mm of a1,
shape=swig vsplit] {
\nodepart{left}{$A_2(a_1)$}
\nodepart{right}{$a_2$} };
\draw[->](a1) to (a2);
\end{tikzpicture}
\end{tkzexample}
\medskip
\noindent This can also be done globally for all split nodes;
here we also make the line color red for right halves.
\begin{tkzexample}[latex=5cm, very small]
\begin{tikzpicture}
\tikzset{swig vsplit={gap=3pt,
line color right=red}}
\node[name=a1,shape=swig vsplit]{
\nodepart{left}{$A_1$}
\nodepart{right}{$a_1$} };
\node[name=a2,shape=swig vsplit,
right=5mm of a1]{
\nodepart{left}{$A_2(a_1)$}
\nodepart{right}{$a_2$} };
\draw[->](a1) to (a2);
\end{tikzpicture}
\end{tkzexample}
\medskip
\eject
\noindent As before, a version for black and white publications:
\begin{tkzexample}[latex=5cm, very small]
\begin{tikzpicture}
\tikzset{line width=1.5pt,
swig vsplit={gap=3pt,
inner line width right=0.5pt}}
\node[name=a1,shape=swig vsplit]{
\nodepart{left}{$A_1$}
\nodepart{right}{$a_1$} };
\node[name=a2,shape=swig vsplit,
right=3mm of a1]{
\nodepart{left}{$A_2(a_1)$}
\nodepart{right}{$a_2$} };
\draw[->,line width=1.5pt,>=stealth]
(a1) to (a2);
\end{tikzpicture}
\end{tkzexample}
\bigskip
\noindent Here is an example with multiple stages:
\begin{tkzexample}[vbox]
\begin{tikzpicture}
\tikzset{line width=1.5pt, outer sep=0pt,
ell/.style={draw,fill=white, inner sep=2pt,
line width=1.5pt},
swig vsplit={gap=5pt,
inner line width right=0.5pt}};
\node[name=l1, ell, shape=ellipse]{$L_1$};
\node[name=a1,right=5mm of l1, shape=swig vsplit]{
\nodepart{left}{$A_1$}
\nodepart{right}{$a_1$} };
\node[name=l2, right=5mm of a1, ell, shape=ellipse]{$L_2(a_1)$};
\node[name=a2,shape=swig vsplit,
right=5mm of l2]{
\nodepart{left}{$A_2(a_1)$}
\nodepart{right}{$a_2$} };
\node[name=y, right=5mm of a2, ell, shape=ellipse]{$Y(a_1,a_2)$};
\draw[->,line width=1.5pt,>=stealth]
(l1) edge (a1)
(l1) edge[out=330,in=210] (a2)
(a1) edge (l2)
(a1) edge[out=15,in=150] (a2)
(a1) edge[out=30,in=150] (y)
(l2) edge (a2)
(a2) edge (y);
\end{tikzpicture}
\end{tkzexample}
\eject
\noindent Expanded nodes showing additional options and anchors.
\begin{tkzexample}[vbox, very small]
\Huge
\begin{tikzpicture}
\pgfsetinnerstrokecolor{blue!10!white} % so inner line col=background
\tikzset{shape example/.style={draw,fill=yellow!30,
inner xsep=10pt,inner ysep=25pt,outer xsep=0cm,outer ysep=0cm},
swig vsplit={line color right=green!30, line color left=red!20,
gap=25pt, line width left= 10pt, line width right=15pt,
inner line width left = 0pt, inner line width right = 4pt}}
\node[name=s,shape=swig vsplit, shape example]
{\nodepart[red!20]{left}{$Y_1(a_1)$}
\nodepart[green!30]{right}{$y_1$}};
\foreach\anchor/\placement in
{north/above, south/below, east/right, west/left,
left base/below, right base/below, right/above, left/above,
left mid/above, mid east/right, mid west/left, base east/right,
base west/left, right mid/above,
142/above, 320/below, center/below}
\draw[shift=(s.\anchor)] plot[mark=x] coordinates{(0,0)}
node[\placement] {\scriptsize\texttt{(s.\anchor)}};
\begin{scope}[yshift=-4cm]
\node[name=s,shape=swig vsplit, shape example]
{\nodepart[red!20]{left}{$Y_1(a_1)$}%
\nodepart[green!30]{right}{$y_1$}};
\foreach\anchor/\placement in
{left center/below, right center/above,
left north/above left, left south/below left,
right north/above right, right south/below right,
north west/above left, south west/below left,
north east/above right, south east/below right}
\draw[shift=(s.\anchor)] plot[mark=x] coordinates{(0,0)}
node[\placement] {\scriptsize\texttt{(s.\anchor)}};
\end{scope}
\end{tikzpicture}
\end{tkzexample}
\bibliographystyle{chicago}
\begin{thebibliography}{}
\bibitem[\protect\citeauthoryear{Richardson and Robins}{Richardson and
Robins}{2013}]{swigs}
Richardson, T.S. and J.M.~Robins (2013).
\newblock Single world intervention graphs (SWIGs): A unification of
counterfactual and graphical approaches to causality.
\newblock Working Paper Number 128. Available at
\url{
http://www.csss.washington.edu/Papers/wp128.pdf}.
\end{thebibliography}
%\bibliography{references}
\end{document}