Professional 3-way Venn diagrams
By: Kate Wall
Tags: Data Visualization, Pandas, Matplotlib, Python, Venn Diagrams

Setup

Let’s begin with data stored in pandas DataFrames. As a standard data structure, we wish to quickly visualize categorical data from three DataFrames or Series. For the purpose of this example, we will consider ten total people distributed across three groups: A, B, and C. The goal is to visualize these groupings using Venn diagrams.

import pandas as pd

groupA =['person1','person2','person3','person4','person5',

'person6','person7']

groupB = ['person1','person2','person3', 'person8','person9']

groupC = ['person1','person2', 'person4', 'person9','person10'] dfA = pd.DataFrame(groupA,columns=[‘A’])

dfB = pd.DataFrame(groupB,columns=[‘B’])

dfC = pd.DataFrame(groupC,columns=[‘C’])

Contents of dfA, dfB, and dfC

3-Way Venn Diagrams

The ideal python data structure for analyzing groupings is the “set.” A set is an unordered grouping of unique items. In the first line, we call the column A of pandas DataFrame dfA as a series. Then, we convert the series to a set.

If your data column has duplicated items, you will need to drop them or transform their names prior to using this method. If you are unsure, call with sum(dfA.A.duplicated()). If this number is greater than zero, address duplicates prior to proceeding.

A = set(dfA.A)

B = set(dfB.B)

C = set(dfC.C)

Subsets of A, B, and C can be found using the set operators & and - to compute intersections (shared components) and differences. A_rest contains the individuals only found in A. AB_only contains the individuals in both A and B not found in C. ABC_overlap contains individuals who have membership in all three groups.

AB_overlap = A & B #compute intersection of set A & set B

AC_overlap = A & C

BC_overlap = B & C

ABC_overlap = A & B & C A_rest = A - AB_overlap - AC_overlap #see left graphic

B_rest = B - AB_overlap - BC_overlap

C_rest = C - AC_overlap - BC_overlap AB_only = AB_overlap - ABC_overlap #see right graphic

AC_only = AC_overlap - ABC_overlap

BC_only = BC_overlap - ABC_overlap

Intersections between subsets

These variables can now be used to generate the Venn using the matplotlib_venn package. When customizing to your data, keep track of the group order!

from collections import Counter

from matplotlib_venn import venn2, venn3

import matplotlib.pyplot as plt sets = Counter() #set order A, B, C

sets['100'] = len(A_rest) #100 denotes A on, B off, C off sets['010'] = len(B_rest) #010 denotes A off, B on, C off

sets['001'] = len(C_rest) #001 denotes A off, B off, C on sets['110'] = len(AB_only) #110 denotes A on, B on, C off

sets['101'] = len(AC_only) #101 denotes A on, B off, C on sets['011'] = len(BC_only) #011 denotes A off, B on, C on sets['111'] = len(ABC_overlap) #011 denotes A on, B on, C on labels = ('Group A', 'Group B', 'Group C')

plt.figure(figsize=(7,7))

ax = plt.gca()

venn3(subsets=sets, set_labels=labels, ax=ax,set_colors=

('darkviolet','deepskyblue','blue'),alpha=0.7)

plt.show()

Default 3-way Venn

Change the color of the “set_label” (e.g. Group A).

This diagram is nice, but it looks more amateur than professional. To jazz it up, we can customize just a several aspects of the visual. First, we can modify the set label colors. See the bolded section of added code.

plt.figure(figsize=(7,7))

ax = plt.gca()

colors = ['darkviolet','deepskyblue','blue']

v = venn3(subsets=sets, set_labels=labels, ax=ax,set_colors=

colors,alpha=0.7) i = 0

for text in v.set_labels:

text.set_color(colors[i])

i+=1 plt.show()

Match the label colors to the subset colors

Change the color of the “subset_label” (e.g. 1,2,3).

Now that the set label colors correspond with the circle sections, we can also modify the number font. For additional clarity, we can change the color, fontsize, and fontweight of the subset label on the Venn diagram.

plt.figure(figsize=(7,7))

ax = plt.gca()

colors = ['darkviolet','deepskyblue','blue']

v = venn3(subsets=sets, set_labels=labels, ax=ax,set_colors=

colors,alpha=0.7)

i = 0

for text in v.set_labels:

text.set_color(colors[i])

i+=1



for text in v.subset_labels:

text.set_color('white')

text.set_fontsize(16)

text.set_fontweight('bold') plt.show()

Make the subset labels readable on the background color

Replace labels with a legend, and add a title.

Once satisfied with these fonts, we might wish to eliminate the colored labels altogether for a more formal effect. Create the legend by generating two lists, handles and labels.

Handles is generated by iterating through the patches of the Venn using the get_patch_id() method in the Venn3 class and adding the components to an empty list. In my experience, it is best to print the handles list on the graphic, and manually write the label list to match.

plt.figure(figsize=(7,7))

ax = plt.gca()

v = venn3(subsets=sets, set_labels=('','',''), ax=ax,set_colors=

colors,alpha=0.7)

for text in v.subset_labels:

text.set_color('white')

text.set_fontsize(16)

text.set_fontweight('bold')



h = []

for i in sets:

h.append(v.get_patch_by_id(i))

l = ['A only','C only','B only','A & C shared','A & B shared',

'B & C shared','A & B & C shared']

ax.legend(handles=h, labels=l, title="Legend",loc='lower left') plt.title('Membership across Three Groups') plt.show()

Eliminate labels and opt for a legend

Customize the legend contents.

Remove elements of the legend that are self-explanatory, redundant, or unimportant. This will guide your audience to the remaining elements you wish to emphasize. To do this, we manually modify the handles and labels lists generated above.

Please note the handles list h has a way of shifting around when counts change. Conveniently, I could call slices of h and l using h[0:3] and l[0:3] for this example. However, if you need to eliminate color patches from the centers of these two lists, you can apply the del h[2] operator to remove elements at specific indexes from handles and labels prior to calling them as arguments in ax.lengend() . For instance, that would remove the element at index 2 from list h . Just remember to keep the lengths of these lists equal.

plt.figure(figsize=(7,7))

ax = plt.gca()

v = venn3(subsets=sets, set_labels=('','',''), ax=ax,

set_colors=colors, alpha=0.7)

for text in v.subset_labels:

text.set_color('white')

text.set_fontsize(16)

text.set_fontweight('bold') ax.legend(handles=h[0:3], labels=l[0:3], title="Legend",

loc='lower left') plt.title('Membership across Three Groups')

plt.show()

Customize the contents of the legend

2-Way Venn Diagrams

These methods can also be applied to 2-way diagrams, which are substantially simpler. The notation of the venn2 class follows that of venn3. All of the above methods can be applied to this base class using the same format.

sets = Counter() #set order A, B

sets['10'] = len(A-AB_overlap) #10 denotes A on, B off

sets['01'] = len(B-AB_overlap) #01 denotes A off, B on

sets['11'] = len(AB_overlap) #11 denotes A on, B on

labels = ('Group A', 'Group B') plt.figure(figsize=(7,7))

ax = plt.gca()

venn2(subsets=sets, set_labels=labels, ax=ax,set_colors=

('darkviolet','deepskyblue'),alpha=0.7) plt.title('Membership across Two Groups')

plt.show()

Default 2-way Venn

That concludes this tutorial.

To some, customizing text content, placement, color, size, or weight in graphics may seem unnecessary. For practical use, it is. However, in formal presentation settings, a clean, clear graphic is crucial. If a picture speaks 1,000 words, use these techniques to make them count.

For more, check out the full notebook on GitHub. Interested in related articles? Read more from the author.