Rachejen - 1 year ago 72

Python Question

I currently have a figure with 5 venn diagram subplots. All 5 diagrams are 2 circle venns and each have a different sum of elements.Refer to this figure.

I would like to know if it is possible to have these 6 subplots all to the same scale? For example, my entire first venn would be scaled to be smaller than the fifth one.

Code below.

Any help most appreciated.

`from matplotlib_venn import venn2`

from matplotlib import pyplot as plt

import numpy as np

figure, axes = plt.subplots(2, 3, figsize=(11.69,8.27))

BSL_20=(313,10,76)

BSL_40=(384,17,150)

BSL_100=(665,8,378)

BSL_100CC=(860,23,879)

BSL_200=(585,17,758)

v1=venn2(BSL_20, set_labels = ('150mm at 50%', '400mm at 25%'), ax=axes[0][0])

v2=venn2(BSL_40, set_labels = ('150mm at 50%', '400mm at 25%'), ax=axes[0][1])

v3=venn2(BSL_100, set_labels = ('150mm at 50%', '400mm at 25%'), ax=axes[0][2])

v4=venn2(BSL_100CC, set_labels = ('150mm at 50%', '400mm at 25%'), ax=axes[1][0])

v5=venn2(BSL_200, set_labels = ('150mm at 50%', '400mm at 25%'), ax=axes[1][1])

v6=venn2(BSL_200, set_labels = ('150mm at 50%', '400mm at 25%'), ax=axes[1][1])

axes[1,2].axis('off')

plt.show()

Answer Source

Try adding this to your code before `plt.show()`

:

```
from matplotlib.cbook import flatten
data = [BSL_20, BSL_40, BSL_100, BSL_100CC, BSL_200]
max_area = max(map(sum, data))
def set_venn_scale(ax, true_area, reference_area=max_area):
s = np.sqrt(float(reference_area)/true_area)
ax.set_xlim(-s, s)
ax.set_ylim(-s, s)
for a, d in zip(flatten(axes), data):
set_venn_scale(a, sum(d))
```

Explanation:

- The patches that
`matplotlib_venn`

draws are scaled so that their total area is 1. The diagram is positioned with its center near the point (0, 0) and axis limits are configured so that the diagram would fit tightly inside. - This means that if you would simply set
`xlim(-1, 1)`

and`ylim(-1, 1)`

for all the subplots, you would get diagrams that all have the same total area (assuming all subplots are shown at the same scale). - If you now need to "scale down" one of the diagrams in order to reduce its area by 2, one way to achieve it is to simply scale up all axis limits by
`sqrt(2)`

. - This is what the code above does: it first identifies the circle-set with the largest actual total area, and then simply scales up the limits of other diagrams proportionally to
`sqrt(max_area/required_area)`

.

You could also cut some slack on the Y axis and pack the code and the diagram tighter as follows:

```
from matplotlib_venn import venn2
from matplotlib.cbook import flatten
from matplotlib import pyplot as plt
import numpy as np
figure, axes = plt.subplots(2, 3, figsize=(11.69,5.5))
BSL_20=(313,10,76)
BSL_40=(384,17,150)
BSL_100=(665,8,378)
BSL_100CC=(860,23,879)
BSL_200=(585,17,758)
data = [BSL_20, BSL_40, BSL_100, BSL_100CC, BSL_200]
max_area = max(map(sum, data))
def set_venn_scale(vd, ax, true_area, reference_area=max_area):
sx = np.sqrt(float(reference_area)/true_area)
sy = max(vd.radii)*1.3
ax.set_xlim(-sx, sx)
ax.set_ylim(-sy, sy)
for a, d in zip(flatten(axes), data):
vd = venn2(d, set_labels = ('150mm at 50%', '400mm at 25%'), ax=a)
set_venn_scale(vd, a, sum(d))
axes[1,2].axis('off')
figure.tight_layout(pad=0.1)
plt.show()
```

Note, though, that `tight_layout`

will start rescaling your subplots if it feels there is not enough space, so check the results (e.g by adding axes around your subplots via `ax.set_axis_on()`

and making sure all the subplots have the same width).