Skip to main content
3 of 4
added 1184 characters in body

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):

postProcessVennDiagram[vd_] := 
 Block[{labels, polygons, rpts, text, r0, hs},
  labels = vd[[2, All, 2, 1, 1, 1, 1]];
  r0 = 3/(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"], #2] &, {polygons, Length /@ labels}];
  text = Graphics[MapThread[Text[Style[#1, 16], #2] &, {Join @@ labels, Join @@ rpts}]];
  Show[vd[[1]], text, ImageSize -> 350]]

postProcessVennDiagram[vd]

enter image description here

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]

enter image description here

Original Answer

There's a very nice Function Repository entry that makes this quite easy:

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}]
 ]

enter image description here