I have recently discovered that simple Venn diagrams are surprisingly popular in bioinformatics. So popular they are, in fact, that thereareseveralbioinformaticsresearchpapers devoted solely to their use. And those are highly accessed papers, let me add! Yet, despite this wild popularity, tools that let you render a decent Venn diagram programmatically seem to be rather scarce.

Vennerable plot

If you google a bit, you will find a bunch of on-line tools of varying degrees of quality and ability (1, 2, 3, 4, 5, 6, 7, 8, 9,...), a Java-based tool, a Perl library, a couple of Python scripts (1, 2), some R libraries (1, 2, 3, 4, 5), and lots of forum discussions. Seems to be plenty, doesn't it? Well, it turns out that if you want your diagram to be area-weighted (i.e. the regions of the diagram should be roughly proportional to the corresponding set sizes), 4 of those 18 links won't do. If you want to generate and configure the diagram conveniently from a script, drop another 9. Then, if you want the diagram to look nice, drop 4 more, and all you are left with is the Vennerable R package. Unfortunately, Vennerable plots are still a pain to configure — even adding a plot title seems to be very tricky, not speaking of highlighting and annotating a region on the diagram.

Having been totally disappointed in the state of the art of contemporary Venn-diagramming tools, I made a small Python package for drawing Venn diagrams that has the necessary flexibility. At least it lets me put plot titles and annotate diagram regions as I fancy.

Eh, I was suspecting that this whole "namespace package" business won't work as expected for at least someone (i.e. distributing a package matplotlib.venn from a separate egg).

That means I need to rename the package to something non-conflicting (e.g. matplotlibvenn instead of matplotlib.venn or the like). I'll fix it today/tomorrow. If you want to try things before, just download the source, rename the matplotlib directory there to something different, edit namespace_packages option in setup.py, and either do python setup.py install or just run python from that directory and do "import whateveryournewname.venn", etc.

Dear Konstantin,
thank you for the package.
I've successfully used it, but am unhappy with the result, since the numbers for subsets/"sub-circles" are not placed correctly within the graph. I've tried playing around with the plt.figure(figsize=xyz)) and the "normalize_to" variable, but the results stay the same.
Do you have any suggestions, tipps??? I would appreciate your help!

Hello. You are free to reposition the elements of the resulting plot to your liking by accessing them directly (as matplotlib objects). Check out the answer to this issue. Note that the picture generated by matplotlib-venn has a width of 1 (i.e. increasing the x coordinate of a label by 0.5 should move it right by half the plot width).

Is it possible to make a circle within a circle? As in, display a set A which fully encompasses set B (which then intersects with a set C, as in a normal diagram? I can't work out how to do this. Any help would be greatly appreciated.

If your data indicate that a circle should be within a circle, that is what you should see, in general. E.g.

venn3(subsets=(1, 0, 1, 1, 1, 0, 1))

I.e. as the data here indicates, the areas of "010" and "011" are both zeros. Consequently, circle "B" must lie completely inside "A".

Admittedly, this configuration seems to produce somewhat unexpected colors (because the regions overlap in a way I did not account for) and some labels are located suboptimally. I'll try to fix it in the next release. So far you may overcome it by tuning the transparency and the colors of certain regions manually, e.g.:

Note: there does not necessarily exist a perfect circle positioning, that will exactly correspond to all seven of your region areas. In particular, the current positioning algorithm only makes sure that the three pairwise circle intersections (AB, BC, AC) have correct areas. It should reflect the "circle within other circle" situation always correctly, though, I think.

Firstly, your parameters are wrong. Namely, the size of the set "101" must be 0 rather than 15, according to your image. So the correct call would bevenn3(subsets=(25, 231, 8, 0, 0, 80, 15))

Secondly, the current layout algorithm will not produce what you want. If you look at the result of the above call it is close to what you need except that one of the bubbles is "stuck" to the wall of another one. The layout algorithm is not smart enough to come up with an idea of aligning the bubbles for a slightly nicer look in this particular special case.

If you really-really need the symmetrically aligned version the simplest way you could try is to draw a two-set diagram and superimpose a third circle on top, e.g.:

# Draw a two-circle diagram
venn2(subsets=(25, 231+65, 8+15))
# Find out the location of the two circles
# (you can look up how its done in the first lines
# of the venn2 function)
from matplotlib_venn._venn2 import compute_venn2_areas, \
solve_venn2_circles
subsets = (25, 231+65, 8+15)
areas = compute_venn2_areas(subsets, normalize_to=1.0)
centers, radii = solve_venn2_circles(areas)
# Now draw the third circle.
# Its area is (15+65)/(25+8+15) times
# that of the first circle,
# hence its radius must be
r3 = radii[0]*sqrt((15+65.0)/(25+8+15))
# Its position must be such that the intersection
# area with C1 is 15/(15+8+25) of C1's area.
# The way to compute the distance between
# the circles by area can be looked up in
# solve_venn2_circles
from matplotlib_venn._math import find_distance_by_area
distance = find_distance_by_area(radii[0], r3,
15.0/(15+8+25)*np.pi*radii[0]*radii[0])
ax = gca()
ax.add_patch(Circle(centers[0] + np.array([distance, 0]),
r3, alpha=0.5, edgecolor=None,
facecolor='red', linestyle=None,
linewidth=0))

.. and then you'll need to play around with the text labels a bit too.

Hi, thanks a lot for your help. I see now where I was going wrong with my numbers. I think I'd rather use the first method, but it looks like it might be a bit painful to get the labels in the right positions, and remove 0 etc. I'll try look at the wiki and sort out the labels, and hopefully I can get something close to my hand-drawn version.

Wow! Thank you so much for your help - I can't tell you how much time and pain this has saved me. You have really renewed my faith in the open source/developer community. Brilliant library and brilliant dev.

Explanation: you do not see the axis background because somewhere within the package I do something like ax.set_axis_off(). This removes the axis rectangle completely. It seemed like a good thing to do for an average Venn diagram. You can switch it back on, by calling set_axis_on() on the axis object. Also, note that by default the Venn diagrams use colors with transparency, which look ugly with a non-white background. You can disable the default transparency setting by giving the "alpha" keyword parameter to the venn* function. This works because the function passes all the keyword arguments it does not know about directly to the Patch objects that make up the diagram.

This particular package won't do more than 3 sets. If you want an unweighed diagram with four sets, check out this script.

An area-weighed diagram for more than three sets won't make too much illustrative sense in most cases I believe, because it is way too underconstrained (i.e. it is only possible to faithfully depict perhaps 10 or so areas out of the total 15 in the diagram).

Nice! I wish this hint were in some place that is easy to google up. (Although this site does come up somewhere on the first page of a "vennerable plot title" query currently, I am not sure most people looking for this answer would find your remark here).

Perhaps you could post it as a self-answered question on stackoverflow?

Hi! I am using your matplotlib_venn library to obtain some figures for our paper about gene expression on cancer. I was wondering: is there any possibility to change the intersection labels (which, in the standard plot produced by your library, describe the size of the intersection) with a personalized label?

Yes. The labels are accessible using the get_label_by_id method of the VennDiagram object, returned by the venn* functions. They are standard matplotlib Text objects, and you are free to do whatever you want with them (change contents, properties, delete, etc).

For example, this will change the text of the label used on the three set intersection:

Of course. Each intersection is a matplotlib PathPatch object, you can access it via code like v.get_patch_by_id('101') (where the parameter identifies the corresponding intersection). From there on you are free to set any properties of the patch to your liking.