3

I was able to modify Loop Space's code (the first answer found here: How to generate all possible Venn diagrams (with the case below) efficiently?) to draw a Venn diagram for four sets using ellipses. It appears to work for individual Venn diagrams, but when I try to use \allvendiagrams, I get an error stating that the dimension is too large. I realize that there are 65,536 possible variations and it would not be practical to try and print a document containing all of them, but I would like to get the code to work if possible. My code is below:

\documentclass[border=3pt,tikz]{standalone}
%\url{https://tex.stackexchange.com/q/67395/86}
\usepackage{tikz}
\usetikzlibrary{positioning,shapes.geometric}
\makeatletter

\def\venn@strip#1#2\venn@STOP{%
  \def\venn@next{#1}%
  \gdef\venn@rest{#2}%
}

\newcommand{\venn}[1]{%
\begin{tikzpicture}
\coordinate (A) at (1.6,0);
\coordinate (B) at (0.3,1);
\coordinate (C) at (-1.6,0);
\coordinate (D) at (-0.3,1);
\coordinate (S-SE) at (5,-4);
\coordinate (S-NW) at (-5,5);
  \edef\venn@rest{#100000000}%
  \foreach \i in {0,...,15} {
  \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) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \pgfmathparse{Mod(floor(\i/2),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
    \path[clip] \pgfmathresult (B) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \pgfmathparse{Mod(floor(\i/4),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
    \path[clip] \pgfmathresult (C) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \pgfmathparse{Mod(floor(\i/8),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
    \path[clip] \pgfmathresult (D) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \fill[rounded corners,gray!80] (S-SE) rectangle (S-NW);
    \fi
  \end{scope}
  }
    \draw[ultra thick] (A) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \draw[ultra thick] (B) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \draw[ultra thick] (C) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \draw[ultra thick] (D) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \draw[ultra thick,rounded corners] (S-SE) rectangle (S-NW);
\end{tikzpicture}
}

\makeatother

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

}
}

\begin{document}
%\venn{0000000000000000} %0
%\venn{0000000000000001} %1
%\venn{0000000000000010} %2
%\venn{0000000000000011} %3
%\venn{0000000000000100} %4
%\venn{0000000000000101} %5
%\venn{0000000000000110} %6
%\venn{0000000000000111} %7
%\venn{0000000000001000} %8
%\venn{0000000010000000} %128
%\venn{0000000011111111} %255
%\venn{1111111111111111} %65535
\allvendiagrams
\end{document}

It should be noted that Overleaf gives the "Dimension too large" error but still produces the Venn diagrams. As expected, it times out when trying to generate all 65,536 variations; I'm currently running them 100 at a time. TexWorks gives the "Dimension too large" error and does not generate anything; I'd like to get the code to work in TexWorks if possible since I do not have a reliable internet connection at home.

3
  • Awesome! I'm getting the error in the inner foreach loop. I suspect that a better routine of stepping through the binary integers would be a good thing to try. Jul 31, 2019 at 17:57
  • (can't believe I misspelled "venn" in "allvendiagrams" ...) Jul 31, 2019 at 17:58
  • @LoopSpace--I cannot claim to understand exactly how your code does what it does, but I was able to figure out how to pick which variation of the Venn diagram I wanted to produce by figuring out which binary digit represented which region. Jul 31, 2019 at 19:50

1 Answer 1

5

I'm not on a device where I can test this fully, but limited tests show that this ought to do what is asked for. As I said in my comment, it appears to be the bit that generates the binary strings that was causing the issues so this reimplements that in a simpler fashion.

"Simpler" is obviously a subjective term! Although the code looks probably more complicated, what it is doing is technically more low-level. The original code worked by taking a number and converting it to a binary string using routines that were fine mathematically but which reached the borders of TeX's number capability. However, it did mean that we could make use of pgfmath's mathematical parser. This code represents a binary number as a string of 0s and 1s. This avoids TeX's upper limit on numbers but does mean that we have to implement the operation "add 1" manually. That's what the macro \step_bin does.

(This code probably isn't as elegant as it could be. It's written using LaTeX3 functions, but I think my naming schemes aren't quite in keeping with proper L3 conventions. Also, it might actually be that LaTeX3's integer handling can cope with large numbers so this might be overkill. I'm not at a device where I can easily test these hypotheses for a bit but someone else might step by with an improvement - consider unaccepting this answer to indicate that there's still stuff to do.)

\documentclass[border=3pt,tikz]{standalone}
%\url{https://tex.stackexchange.com/q/67395/86}
\usepackage{tikz}
\usepackage{expl3}
\usepackage{xparse}
\usetikzlibrary{positioning,shapes.geometric}

\ExplSyntaxOn

\tl_new:N \l__bin_tl
\tl_new:N \l__bin_tmpa_tl
\int_new:N \l__bin_tmpa_int

\cs_new_nopar:Npn \reset_bin {
\tl_set:Nn \l__bin_tl {0000000000000000}
}

\cs_new_nopar:Npn \step_bin {
\tl_clear:N \l__bin_tmpa_tl
\int_set:Nn \l__bin_tmpa_int {1}
\tl_map_inline:Nn \l__bin_tl {
\int_add:Nn \l__bin_tmpa_int {##1}
\tl_put_left:Nx \l__bin_tmpa_tl { \int_mod:nn {\l__bin_tmpa_int} {2}}
\int_set:Nn \l__bin_tmpa_int { (\l__bin_tmpa_int - \int_mod:nn {\l__bin_tmpa_int}{2})/2}
}
\tl_set_eq:NN \l__bin_tl \l__bin_tmpa_tl
}

\DeclareDocumentCommand \AllVenns {} {
\reset_bin
\prg_replicate:nn {65536} {
\exp_args:NV \venn \l__bin_tl
\step_bin
}
}

\ExplSyntaxOff

\makeatletter

\def\venn@strip#1#2\venn@STOP{%
  \def\venn@next{#1}%
  \gdef\venn@rest{#2}%
}

\newcommand{\venn}[1]{%
\begin{tikzpicture}
\coordinate (A) at (1.6,0);
\coordinate (B) at (0.3,1);
\coordinate (C) at (-1.6,0);
\coordinate (D) at (-0.3,1);
\coordinate (S-SE) at (5,-4);
\coordinate (S-NW) at (-5,5);
  \edef\venn@rest{#100000000}%
  \foreach \i in {0,...,15} {
  \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) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \pgfmathparse{Mod(floor(\i/2),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
    \path[clip] \pgfmathresult (B) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \pgfmathparse{Mod(floor(\i/4),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
    \path[clip] \pgfmathresult (C) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \pgfmathparse{Mod(floor(\i/8),2) == 1 ? "(S-SE) rectangle (S-NW)" : ""}
    \path[clip] \pgfmathresult (D) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \fill[rounded corners,gray!80] (S-SE) rectangle (S-NW);
    \fi
  \end{scope}
  }
    \draw[ultra thick] (A) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \draw[ultra thick] (B) ellipse [x radius=3cm, y radius=1.5cm, rotate=50];
    \draw[ultra thick] (C) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \draw[ultra thick] (D) ellipse [x radius=3cm, y radius=1.5cm, rotate=-50];
    \draw[ultra thick,rounded corners] (S-SE) rectangle (S-NW);
\end{tikzpicture}
}

\makeatother

\begin{document}
%\venn{0000000000000000} %0
%\venn{0000000000000001} %1
%\venn{0000000000000010} %2
%\venn{0000000000000011} %3
%\venn{0000000000000100} %4
%\venn{0000000000000101} %5
%\venn{0000000000000110} %6
%\venn{0000000000000111} %7
%\venn{0000000000001000} %8
%\venn{0000000010000000} %128
%\venn{0000000011111111} %255
%\venn{1111111111111111} %65535
%\allvendiagrams
\AllVenns
\end{document}
2
  • 2
    It seems to be working. Obviously, it's going to take a while to compile. Looking at the code, I'm not sure how it's simpler, but I'll take your word for it. Can you offer a suggestion on where to find resources to explain how your code works? I'd like to learn how to do what you've done here and how to write my own .cls and .sty files. Jul 31, 2019 at 20:07
  • I've added a bit of comentary, but do take note of my remarks in the parentheses! This is definitely "get sth that works" code rather than "the best" code. Aug 1, 2019 at 7:39

You must log in to answer this question.

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