Edit 02
There was a small bug in dealing with empty sets (e.g. the one that arises with the chosen random seed below). This is now fixed. Additionally, figured I'd play around with the new-ish HardcorePointProcess
functionality to get more evenly-spaced labels. Seems to work reasonably well (you might have to adjust the radius, r0
):
shrinkPolygon[polygon_,sf_:0.85] := TransformedRegion[polygon,ScalingTransform[{sf, sf}, RegionCentroid[polygon]]]
postProcessVennDiagram[vd_] :=
Block[{labels, polygons, rpts, text, r0, hs},
labels = vd[[2, All, 2, 1, 1, 1, 1]];
r0 = 32/(Sqrt[n] Sqrt[\[Pi]]) /. n -> Length[Join @@ labels];
hs = HardcorePointProcess[1000, r0, 2];
polygons = Cases[vd[[1, 1]], {Null, Polygon[a__]} :> Polygon[a]];
rpts = MapThread[Take[RandomPointConfiguration[hs, DiscretizeRegion[#1]]["Points"]shrinkPolygon[DiscretizeRegion[#1]]]["Points"], #2] &, {polygons, Length /@ labels}];
text = Graphics[MapThread[Text[Style[#1, 16], #2] &, {Join @@ labels, Join @@ rpts}]];
Show[vd[[1]], text, ImageSize -> 350]]
postProcessVennDiagram[vd]
Seems to work reasonably well. Note you might have to adjust the radius, r0
, and scaling factor, sf
, in the polygon shrinking (which I added to ensure the labels are completely maintained inside the regions).
Edit 01
It should be possible to post-process the result to place the elements inside their corresponding region. For example, here I'm using RandomPoint
but I suspect you can use some sort of Lloyd relaxation on a voronoi mesh to get them more evenly spaced:
postProcessVennDiagram[vd_] :=
Block[{labels, length, polygons, rpts, text},
labels = vd[[2, All, 2, 1, 1, 1, 1]];
polygons = Cases[vd[[1, 1]], {Null, Polygon[a__]} :> Polygon[a]];
rpts = MapThread[RandomPoint, {polygons, Length /@ labels}];
text = Graphics[MapThread[Text[Style[#1, 16], #2] &, {Join @@ labels, Join @@ rpts}]];
Show[vd[[1]], text, ImageSize -> 350]]
postProcessVennDiagram[vd]
Original Answer
There's a very nice Function Repository entry that makes this quite easy:
SeedRandom[25];
vd=With[{
a = RandomSample[Range[3, 30], 20],
b = RandomSample[Range[2, 40], 20],
c = RandomSample[Range[4, 49], 20]
},
ResourceFunction["VennDiagram"][{a, b, c}]
]