Generate all 16 possible 2-variable shaded Venn diagrams in TikZ?

Let P and Q be two statements, each with 2 possible truth values: true (T) or false (F). These component statements P and Q can be joined by 16 possible binary connectives to form 16 unique simple compound statements, each of which can be illustrated with Venn diagrams (see previous link).

I have seen several solutions given in this question for generating a Venn diagram, however none of these seems to be easily tweaked to get the other 15 out of 16 cases. Actually, my question is essentially the 2-variable version of this question.

The solution I'm looking for:

Ideally, you could get the TikZ figure you want by typing

• TTTT to shade all 4 regions
• FFFF to shade no regions
• FTTT to shade all regions except the intersection
• TFFF to shade only the intersection
• TTFF to shade only the left circle
• FFTT to shade the complement of the left circle
• etc...

Is there a TikZ algorithm that could generate any one of the 16 possible Venn diagrams with a simple tweak in the code like this? Thanks for your help!

No clipping or even-odd-rule required:

\documentclass[tikz,border=5]{standalone}
\tikzset{%
v 0/.style={fill=white}, v 1/.style={fill=blue!30},
pics/venn/.style args={#1#2#3#4}{code={%
\fill [v #1/.try] (-2,-1.5) rectangle (2,1.5);
\fill [v #2/.try] (90:sin 60) arc (120:-120:1) arc (-60:60:1);
\fill [v #3/.try] (90:sin 60) arc (60:300:1)   arc (240:120:1);
\fill [v #4/.try] (90:sin 60) arc (120:240:1)  arc (-60:60:1);
\draw (-2,-1.5) rectangle (2,1.5)
(90:sin 60) arc (120:-120:1) arc (-60:60:1)
arc (60:300:1) arc (240:120:1) -- cycle;
}}}
\pgfmathsetbasenumberlength{4}% <- Very important!
\begin{document}
\begin{tikzpicture}[x=1em,y=1em]
\foreach \i in {0,...,15}{
\pgfmathdectobase\n{\i}{2}
\pic at ({mod(\i, 4)*6}, {-floor(\i/4)*4}) {venn/.expanded=\n};
}
\end{tikzpicture}
\end{document}


This could be applied as follows:

\documentclass[border=5]{standalone}
\usepackage{tikz,array,centernot,amsmath,mathrsfs}
\setlength{\extrarowheight}{2em}
\tikzset{%
v 0/.style={fill=white}, v 1/.style={fill=blue!30},
pics/venn/.style args={#1#2#3#4}{code={%
\fill [v #4/.try] (-2,-1.5) rectangle (2,1.5);
\fill [v #3/.try] (90:sin 60) arc (120:-120:1) arc (-60:60:1);
\fill [v #2/.try] (90:sin 60) arc (60:300:1)   arc (240:120:1);
\fill [v #1/.try] (90:sin 60) arc (120:240:1)  arc (-60:60:1);
\draw (-2,-1.5) rectangle (2,1.5)
(90:sin 60) arc (120:-120:1) arc (-60:60:1)
arc (60:300:1) arc (240:120:1) -- cycle;
}}}
\newcommand\venn[2][]{{\tikz[every venn/.try, #1]\pic{venn/.expanded=#2};}}
\tikzset{every venn/.style={x=1em, y=1em, baseline=-.666ex,
v 1/.style={fill=gray}}}
\begin{document}
$\displaystyle \begin{array}{|c|c|c|c|} \hline \textrm{Truth Table} & \textrm{Venn Diagram} & \textrm{Connective} & \textrm{Connective Name} \\ \hline FFFF & \venn{0000} & \mathscr{P} \perp \mathscr{Q} & \textrm{Contradiction} \\ FFFT & \venn{0001} & \mathscr{P} \overline{\lor} \mathscr{Q} & \textrm{Nondisjunction (Nor)} \\ FFTF & \venn{0010} & \mathscr{P} \centernot\impliedby \mathscr{Q} & \textrm{Converse Nonimplication} \\[2em] \hline \end{array}$
\end{document}


And here's a 3-variable version:

\documentclass[tikz,border=5]{standalone}
\tikzset{v 0/.style={fill=white}, v 1/.style={fill=blue!30},
venn path 1/.style={insert path={
(90:1/sqrt 3) arc (60:120:1) arc (180:0:1) arc (60:120:1) -- cycle }},
venn path 2/.style={insert path={
(90:1/sqrt 3) arc (120:180:1) arc (240:180:1) arc (120:60:1) -- cycle }},
venn path 3/.style={insert path={
(90:1/sqrt 3) arc (120:180:1) arc (240:300:1) arc (0:60:1) -- cycle }},
pics/venn 3/.style args={#1#2#3#4#5#6#7#8}{code={%
\fill [v #1] (-2,-2) rectangle (2,2);
\fill [v #2, rotate=240, venn path 1];
\fill [v #3, rotate=120, venn path 1];
\fill [v #4, venn path 1];
\fill [v #5, rotate=240, venn path 2];
\fill [v #6, rotate=120, venn path 2];
\fill [v #7, venn path 2];
\fill [v #8, venn path 3];
\draw (90:1/sqrt 3) circle [radius=1] (210:1/sqrt 3) circle [radius=1]
(330:1/sqrt 3) circle [radius=1] (-2, -2) rectangle (2,2);
}}}
\pgfmathsetbasenumberlength{8}% Still very important!
\begin{document}
\begin{tikzpicture}[x=1em,y=1em]
\foreach \i in {0,...,255}{
\pgfmathdectobase\n{\i}{2}
\pic at ({mod(\i, 16)*4}, {-floor(\i/16)*4}) {venn 3/.expanded=\n};
}
\end{tikzpicture}
\end{document}


• Truly beautiful. – jub0bs Sep 8 '15 at 9:08
• Thanks for your answer Mark - I love it. If I want to call a specific one of the set, e.g. type \venn{TTFF} to output one with only the left circle shaded, how can I do that? – Mathemanic Sep 8 '15 at 15:06
• @EthanAlvaree \newcommand\venn[2][]{{\pgfmathsetbasenumberlength{4}\tikz[#1]\pic{venn/.expanded=#2};}} should do it. Then use \venn{0011}. Note, that the argument is0011 not 1100 (it made more sense to me when thinking in binary), and the \venn command puts each diagram in a separate tikzpicture. – Mark Wibrow Sep 8 '15 at 15:43
• Is there any way I can let 1100 be the left circle and 1010 be the right circle? – Mathemanic Sep 8 '15 at 18:10
• @EthanAlvaree just reverse the order of the arguments in the fill commands where it says [v #1/.try]. Currently, the sequence goes (line by line) from v #1 to v #4. Just do it the other way around. – Mark Wibrow Sep 8 '15 at 19:43

Well you can just remove the (C) and you are done

\documentclass{article}
\usepackage{tikz}
\makeatletter
\def\venn@strip#1#2\venn@STOP{\def\venn@next{#1}\gdef\venn@rest{#2}}

\newcommand{\venn}[1]{%
\begin{tikzpicture}[scale=0.2]
\coordinate (A) at (0,0);
\coordinate (B) at (2,0);
\coordinate (S-SE) at (5,-3);
\coordinate (S-NW) at (-3,{sqrt(3)+3});
\edef\venn@rest{#10000}%
\foreach \i in {0,...,3} {
\begin{scope}[even odd rule]
\expandafter\venn@strip\venn@rest\venn@STOP
\ifnum\venn@next=1\relax
\pgfmathparse{Mod(\i,2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
\path[clip] \pgfmathresult (A) circle[radius=2];
\pgfmathparse{Mod(floor(\i/2),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
\path[clip] \pgfmathresult (B) circle[radius=2];
\pgfmathparse{Mod(floor(\i/4),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
\fill[rounded corners,red] (S-SE) rectangle (S-NW);
\fi
\end{scope}
}
\draw[ultra thick] (A) circle[radius=2];
\draw[ultra thick] (B) circle[radius=2];
\draw[ultra thick,rounded corners] (S-SE) rectangle (S-NW);
\end{tikzpicture}
}

\makeatother

\newcommand{\allvendiagrams}{%
\foreach \j in {0,...,15} {%
\def\venncode{}%
\foreach \k in {0,...,3} {%
\pgfmathparse{Mod(floor(\j/2^\k),2) == 1 ? "\venncode1" : "\venncode0"}%
\global\let\venncode=\pgfmathresult%
}
\venn{\venncode}%
}\par%
}

\begin{document}
\venn{1000}
\venn{0100}
\venn{1100}
\allvendiagrams
\end{document}


• Hi Percusse, thanks for your answer! Do you know how we can make the circles fit the square better? Right now I think the figure is still designed for 3 circles instead of 2, which is why the circles aren't taking up the entire square. – Mathemanic Sep 7 '15 at 20:28
• @EthanAlvaree Change the location of North west coordinate a little lower – percusse Sep 7 '15 at 21:12
• Hi Percusse, changing the value to sqrt(3)+1.5 seems to work. One more question: the code seems to have the circles backward. That is, it thinks TTFF is the right circle (but it should be left), and it thinks TFTF is the left circle (but it should be right). How can I fix this? – Mathemanic Sep 8 '15 at 5:58
• @EthanAlvaree Mark Wibrow's answer is more tempting so I would recommend using that one, though I'll check if this is salvagable too later when I have time. The solution is to change the order of the clipping etc. to reverse the arguments. – percusse Sep 8 '15 at 9:11

The areas in the diagrams are drawn with a combination of clip and fill commands. Each bit position encodes one of the four intersection free areas of the diagram. These areas are drawn independently.

\documentclass{article}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
\def\w{1.35}
\def\h{1}
\def\sep{.2}
\pgfmathsetmacro\Ax{\h/2}
\pgfmathsetmacro\Bx{\w - \h/2}
\pgfmathsetmacro\My{\h/2}
\def\vennfill 1#1#2#3#4{%
\ifnum#1=1 %
\begin{scope}
\clip
(0, 0) rectangle (\w, \h)
(\Ax, \My) circle[]
;
\clip
(0, 0) rectangle (\w, \h)
(\Bx, \My) circle[]
;
\fill
(0, 0) rectangle (\w, \h)
;
\end{scope}
\fi
\ifnum#2=1 %
\begin{scope}
\clip
(\Bx, \My) circle[]
;
\fill[even odd rule]
(\Ax, \My) circle[]
(\Bx, \My) circle[]
;
\end{scope}
\fi
\ifnum#3=1 %
\begin{scope}
\clip (\Ax, \My) circle[];
\fill[even odd rule]
(\Ax, \My) circle[]
(\Bx, \My) circle[]
;
\end{scope}
\fi
\ifnum#4=1 %
\clip (\Ax, \My) circle[];
\clip (\Bx, \My) circle[];
\fill (\Ax, \My) circle[];
\fi
\end{scope}
}%
\path[
venn/.pic={
\expandafter\expandafter\expandafter\vennfill\tikzpictext
(0, 0) rectangle (\w, \h)
(\h/2, \h/2) circle[]
(\w-\h/2, \h/2) circle[]
;
}
]
\foreach \r in {0, ..., 3} {
\foreach \c [evaluate=\c as \bin using bin(\r*4+\c+16)] in {0, ..., 3} {
(\c*\w + \c*\sep, -\r*\h - \r*\sep)
pic[fill=red, pic text=\bin] {venn}
}
}
;
\end{tikzpicture}
\end{document}


And here's a version in Metapost for comparison. This exploits a feature of buildcycle with two circular paths that was discussed in my answer to this quesion.

prologues := 3;
outputtemplate := "%j%c.eps";

color venn_color; venn_color = 0.8[blue,white];
vardef venn(expr p, q, r, s) =
save a, b, c, d, f, u; path a,b,c,d, f[]; u = 1cm;
f1 = fullcircle scaled 1u shifted -(1/4u,0);
f2 = fullcircle scaled 1u shifted +(1/4u,0);
a = buildcycle(reverse f1, f2);
b = buildcycle(f1 rotatedabout(center f1, 180), f2);
c = a rotated 180;
d = unitsquare shifted -(1/2,1/2) xscaled 2u yscaled 1.414u;
image(unfill d; if p=1: fill d withcolor venn_color;
unfill a; unfill b; unfill c; fi
if q=1: fill a withcolor venn_color; fi
if r=1: fill b withcolor venn_color; fi
if s=1: fill c withcolor venn_color; fi
draw a; draw c; draw d;)
enddef;

beginfig(1);
for i=0 upto 1: for j=0 upto 1: for k=0 upto 1: for l=0 upto 1:
x0 := 180i+90j; y0 := 120k+60l;
draw venn(i,j,k,l) shifted z0;
label(decimal i & decimal j & decimal k & decimal l, z0 shifted 27 down);
endfor; endfor; endfor; endfor;
endfig;

end.