![如何高效地生成所有可能的维恩图(如下图所示)?](https://linux22.com/image/253917/%E5%A6%82%E4%BD%95%E9%AB%98%E6%95%88%E5%9C%B0%E7%94%9F%E6%88%90%E6%89%80%E6%9C%89%E5%8F%AF%E8%83%BD%E7%9A%84%E7%BB%B4%E6%81%A9%E5%9B%BE%EF%BC%88%E5%A6%82%E4%B8%8B%E5%9B%BE%E6%89%80%E7%A4%BA%EF%BC%89%EF%BC%9F.png)
我能画维恩图但现在我的问题比逐一绘制维恩图更复杂。我需要高效地绘制所有可能的维恩图。我需要一种组合方法,因为有 256 种组合。
让我们选择以下集合作为要考虑的情况。二进制数字标签用于唯一标识每个“原子”区域。我的定义:原子区域不包含任何较小的区域。
因为有 8 个原子区域,每个区域都可以被选中或不被选中以组成新的化合物区域。因此有 2^8 种方法。
如何有效地生成所有可能的维恩图(上述情况)?
目标是生成 256 个维恩图,每个图都有一个独特的彩色复合区域,并具有相关的集合操作。
让我们使用 8 位整数来表示每个图表。
第一位(最左边的位或最高有效位)代表区域000
。
第二位代表区域100
。
...
最低有效位代表区域111
。
位0
表示不连接,产生新的复合区域。1
否则。
如果第一个图的补码为,AuBuC
那么它的二进制表示形式为1000 0000
。1111 1111
表示S
。等等等等!
问题表
问题表将要求学生为每个红色化合物下图中每个图表中的区域。
...
答案1
好的,这是一些代码:
\documentclass{standalone}
%\url{https://tex.stackexchange.com/q/67395/86}
\usepackage{tikz}
\makeatletter
\def\venn@strip#1#2\venn@STOP{%
\def\venn@next{#1}%
\gdef\venn@rest{#2}%
}
\newcommand{\venn}[1]{%
\begin{tikzpicture}
\coordinate (A) at (0,0);
\coordinate (B) at (2,0);
\coordinate (C) at (1,{sqrt(3)});
\coordinate (S-SE) at (5,-3);
\coordinate (S-NW) at (-3,{sqrt(3)+3});
\edef\venn@rest{#100000000}%
\foreach \i in {0,...,7} {
\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)" : ""}
\path[clip] \pgfmathresult (C) circle[radius=2];
\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] (C) circle[radius=2];
\draw[ultra thick,rounded corners] (S-SE) rectangle (S-NW);
\end{tikzpicture}
}
\makeatother
\newcommand{\allvendiagrams}{
% To generate the lot:
\foreach \j in {0,...,255} {
\def\venncode{}
\foreach \k in {0,...,7} {
\pgfmathparse{Mod(floor(\j/2^\k),2) == 1 ? "\venncode1" : "\venncode0"}
\global\let\venncode=\pgfmathresult
}
\venn{\venncode}
}
}
\begin{document}
\venn{10000000}
\venn{01000000}
\venn{11000000}
\end{document}
结果如下:
我几乎肯定会对不同的区域使用不同的代码 - 我选择了更简单的代码。规则是1
第 k 位的 a 填充第 k 个区域,标签和区域之间的对应关系是将 k 写成二进制数,然后如果设置了位,则在内部使用该圆圈,如果没有,则在外部使用该圆圈。最后,我们在上面绘制区域和圆圈。我没有追求太多的可定制性,但希望可以很明显地看出需要更改哪些内容才能使其看起来不同。
编辑自提问者:通过使用\documentclass[border=3pt,tikz]{standalone}
和调用\allvendiagrams
而不是\venn{10000000}\venn{01000000}\venn{11000000}
,输出将显示所有维恩图,如下所示。但肯定不是 GIF。
答案2
这可以做得更优雅,但无论如何它都能工作。基于对是否可以用纯色填充(A 联合 B 联合 C)的补集,但其余区域保持透明?
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\tikzstyle{reverseclip}=[insert path={(current page.north east) --
(current page.south east) --
(current page.south west) --
(current page.north west) --
(current page.north east)}
]
\tikzset{
venn0/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (30:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (-210:0.7cm) circle [radius=1cm] [reverseclip];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn1/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm];
\path [clip] (30:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (-210:0.7cm) circle [radius=1cm] [reverseclip];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn2/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (30:0.7cm) circle [radius=1cm];
\path [clip] (-210:0.7cm) circle [radius=1cm] [reverseclip];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn3/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (30:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (-210:0.7cm) circle [radius=1cm];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn4/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (30:0.7cm) circle [radius=1cm] ;
\path [clip] (-210:0.7cm) circle [radius=1cm] ;
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn5/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm];
\path [clip] (30:0.7cm) circle [radius=1cm] [reverseclip];
\path [clip] (-210:0.7cm) circle [radius=1cm];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn6/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm];
\path [clip] (30:0.7cm) circle [radius=1cm] ;
\path [clip] (-210:0.7cm) circle [radius=1cm] [reverseclip];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
venn7/.code={
\begin{scope}
\begin{pgfinterruptboundingbox}
\path [clip] (-90:0.7cm) circle [radius=1cm];
\path [clip] (30:0.7cm) circle [radius=1cm] ;
\path [clip] (-210:0.7cm) circle [radius=1cm];
\end{pgfinterruptboundingbox}
\fill [orange] (-2,-2) rectangle (2,2);
\end{scope}
},
vennoutlines/.code={
\draw (-90:0.7cm) circle [radius=1cm];
\draw (30:0.7cm) circle [radius=1cm];
\draw (-210:0.7cm) circle [radius=1cm];
}
}
\noindent%
\foreach \a in {0,1}
\foreach \b in {0,1}
\foreach \c in {0,1}
\foreach \d in {0,1}
\foreach \e in {0,1}
\foreach \f in {0,1}
\foreach \g in {0,1}
\foreach \h in {0,1}{%
\begin{tikzpicture}[remember picture, scale=0.2]
\ifnum\a=0
\tikzset{venn0}
\fi
\ifnum\b=0
\tikzset{venn1}
\fi
\ifnum\c=0
\tikzset{venn2}
\fi
\ifnum\d=0
\tikzset{venn3}
\fi
\ifnum\e=0
\tikzset{venn4}
\fi
\ifnum\f=0
\tikzset{venn5}
\fi
\ifnum\g=0
\tikzset{venn6}
\fi
\ifnum\h=0
\tikzset{venn7}
\fi
\tikzset{vennoutlines}
\end{tikzpicture}
}
\end{document}
答案3
这是我的解决方案。它就像杰克的解决方案,但有一些不同。我计算了“漂亮的”圆半径和中心间距(2
和2*sqrt{3}
),因此我可以直接使用坐标并避免reverseclip
,这缩短了区域的定义。此外,我的foreach
循环使用颜色作为变量,这样您就可以避免\ifnum \fi
构造。最后\phantom{X}
只是让最后一张图片与其他 15 张图片保持在同一行。我不知道速度有多快杰克的代码是,但是我的很慢。
\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\begin{document}
\newcommand{\regionA}[1]
{ \fill[#1] (30:2) arc (60:0:{2*sqrt(3)}) arc (-60:120:{2*sqrt(3)}) arc (60:0:{2*sqrt(3)});
}
\newcommand{\regionB}[1]
{ \fill[#1] (150:2) arc (180:120:{2*sqrt(3)}) arc (60:240:{2*sqrt(3)}) arc (180:120:{2*sqrt(3)});
}
\newcommand{\regionC}[1]
{ \fill[#1] (270:2) arc (240:300:{2*sqrt(3)}) arc (360:180:{2*sqrt(3)}) arc (240:300:{2*sqrt(3)});
}
\newcommand{\regionAB}[1]
{ \fill[#1] (30:2) arc (0:60:{2*sqrt(3)}) arc (120:180:{2*sqrt(3)}) arc (120:60:{2*sqrt(3)});
}
\newcommand{\regionAC}[1]
{ \fill[#1] (30:2) arc (60:0:{2*sqrt(3)}) arc (300:240:{2*sqrt(3)}) arc (-60:0:{2*sqrt(3)});
}
\newcommand{\regionBC}[1]
{ \fill[#1] (150:2) arc (120:180:{2*sqrt(3)}) arc (240:300:{2*sqrt(3)}) arc (240:180:{2*sqrt(3)});
}
\newcommand{\regionABC}[1]
{ \fill[#1] (30:2) arc (60:120:{2*sqrt(3)}) arc (180:240:{2*sqrt(3)}) arc (-60:0:{2*sqrt(3)});
}
\newcommand{\regionDarkside}[1]
{ \fill[#1,even odd rule] (90:4) arc (120:-60:{2*sqrt(3)}) arc (360:180:{2*sqrt(3)}) arc (240:60:{2*sqrt(3)}) (0,0) circle (7);
}
\newcommand{\mycolor}{blue!50!cyan}
\newcommand{\mynocolor}{white}
\foreach \a in {\mycolor,\mynocolor}
{ \foreach \b in {\mycolor,\mynocolor}
{ \foreach \c in {\mycolor,\mynocolor}
{ \foreach \d in {\mycolor,\mynocolor}
{ \foreach \e in {\mycolor,\mynocolor}
{ \foreach \f in {\mycolor,\mynocolor}
{ \foreach \g in {\mycolor,\mynocolor}
{ \foreach \h in {\mycolor,\mynocolor}
{ \begin{tikzpicture}[scale=0.05]
\regionA{\a}
\regionB{\b}
\regionC{\c}
\regionAB{\d}
\regionAC{\e}
\regionBC{\f}
\regionABC{\g}
\regionDarkside{\h}
\draw (30:2) circle ({2*sqrt(3)});
\draw (150:2) circle ({2*sqrt(3)});
\draw (270:2) circle ({2*sqrt(3)});
\draw (0,0) circle (7);
\clip (0,0) circle (7);
\useasboundingbox (0,0) circle (7);
\end{tikzpicture}
}
}
}
}
}
}
}
}
\phantom{X}
\end{document}
答案4
这是 metapost 版本(使用 lualatex 编译)。部分输出:
\documentclass{article}
\usepackage{luamplib}
\begin{document}
\begin{mplibcode}
u:=10;
path p[];
picture r[];
numeric k[];
cmykcolor mycol;
mycol:=(0.21,0.12,0,0.07);
z1 = (u/4,-(u/4)/sqrt(3));
p1 = fullcircle scaled u;
p2 = p1 shifted (u/2,0);
p3 = p1 shifted (u/4,-u/4*sqrt(3));
p4 = unitsquare scaled 1.6u shifted (-u/2-.05*u,-u);
p.1 = buildcycle(p1,p2,reverse(p3));
p.2 = buildcycle(p1,reverse(p2),reverse(p3));
p.3 = buildcycle(reverse(p1),reverse(p2),reverse(p3));
r0:=image(draw p1; draw p2; draw p3; draw p4;);
drawoptions(withcolor mycol);
r1:=image(fill p4; unfill p1;unfill p2;unfill p3;);
r2:=image(fill p.1);
r3:=image(fill p.2);
r4:=image(fill p.3);
r5:=image(fill p.1 rotatedabout(z1,120));
r6:=image(fill p.1 rotatedabout(z1,240));
r7:=image(fill p.2 rotatedabout(z1,120));
r8:=image(fill p.2 rotatedabout(z1,240));
drawoptions();
% this converts a number to binary
vardef tobinary(expr n)=
save m; m = n;
j:= 1;
forever: exitunless m>0;
b:= m mod 2;
m:= floor (m/2);
k[j]:=b;
j:=j+1;
endfor;
k[0]:= j-1;
enddef;
beginfig(1);
for i = 0 upto 255:
drawoptions(shifted (1.6*u*(i div 16), -1.6*u*(i mod 16)));
tobinary(i);
for j = 1 upto k[0]:
if k[j]=1: draw r[j]; fi;
endfor;
draw r[0];
endfor;
endfig;
end;
\end{mplibcode}
\end{document}