20

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!

1

4 Answers 4

43

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}

enter image description here

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}

enter image description here

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}

enter image description here

11
  • 9
    Truly beautiful.
    – jub0bs
    Commented Sep 8, 2015 at 9:08
  • 1
    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? Commented Sep 8, 2015 at 15:06
  • 3
    @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. Commented Sep 8, 2015 at 15:43
  • Is there any way I can let 1100 be the left circle and 1010 be the right circle? Commented Sep 8, 2015 at 18:10
  • 1
    @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. Commented Sep 8, 2015 at 19:43
17

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}

enter image description here

4
  • 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. Commented Sep 7, 2015 at 20:28
  • @EthanAlvaree Change the location of North west coordinate a little lower
    – percusse
    Commented Sep 7, 2015 at 21:12
  • 1
    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? Commented Sep 8, 2015 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
    Commented Sep 8, 2015 at 9:11
14

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}
  \pgfmathsetmacro\rad{\h*.35}
  \def\sep{.2}
  \pgfmathsetmacro\Ax{\h/2}
  \pgfmathsetmacro\Bx{\w - \h/2}
  \pgfmathsetmacro\My{\h/2}
  \def\vennfill 1#1#2#3#4{%
    \begin{scope}[radius=\rad, even odd rule]
      \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
      \draw[radius=\rad]
        (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}

Result

13

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.

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .