import os
import matplotlib.pyplot as plt
from matplotlib import font_manager
from matplotlib.patches import Rectangle, Circle, FancyArrowPatch
fp = "Font" if os.path.isdir("Font") else "../Font"
for f in font_manager.findSystemFonts(fontpaths=[fp]):
font_manager.fontManager.addfont(f)
plt.rcParams["font.family"] = "Inter"
INK, ACC, BOX = "#242424", "#3a7ca5", "#c0632f"
GFILL, GEDGE = "#bfe0c4", "#3c8c57"
fig, ax = plt.subplots(figsize=(11.5, 5.2))
ax.set_xlim(0, 23); ax.set_ylim(0, 11); ax.axis("off")
ax.text(4.3, 10.2, "In an UpSet plot", ha="center", fontsize=13, fontweight="bold", color=INK)
sizes = [8, 6, 4, 2]; bxs = [1.7, 3.3, 4.9, 6.5]; bw0 = 1.15; base = 4.6; maxh = 3.9
ax.plot([1.2, 1.2], [base, base + maxh + 0.2], color="#aaaaaa", lw=1)
ax.text(0.9, base + maxh / 2, "intersection\nsize", ha="right", va="center", fontsize=8.5, color="#777777", rotation=90)
for x, sz in zip(bxs, sizes):
h = maxh * sz / max(sizes)
ax.add_patch(Rectangle((x, base), bw0, h, facecolor=GFILL, edgecolor=GEDGE, lw=1.2))
ax.text(x + bw0 / 2, base + h + 0.15, str(sz), ha="center", va="bottom", fontsize=9.5, color=GEDGE, fontweight="semibold")
ax.add_patch(Rectangle((bxs[0], base), bw0, maxh, fill=False, edgecolor=BOX, lw=2.2, ls=(0, (4, 2)), zorder=6))
rows = ["Flu", "Ibu", "Ace"]; row_y = [3.6, 2.9, 2.2]
member = [[0, 0, 1, 1], [1, 0, 1, 1], [1, 1, 0, 1]]
for r, sy in enumerate(row_y):
ax.text(1.15, sy, rows[r], ha="right", va="center", fontsize=9, color=INK)
for c, x in enumerate(bxs):
ax.add_patch(Circle((x + bw0 / 2, sy), 0.14, facecolor=GEDGE if member[r][c] else "#d4d4d4", edgecolor="none", zorder=3))
for c, x in enumerate(bxs):
ys = [row_y[r] for r in range(3) if member[r][c]]
if len(ys) > 1:
ax.plot([x + bw0 / 2] * 2, [min(ys), max(ys)], color=GEDGE, lw=1.6, zorder=2)
ex0, ey0, ew, eh = 14.0, 2.2, 3.0, 6.8
hx1 = bxs[0] + bw0
ax.plot([hx1, ex0], [base + maxh, ey0 + eh], color=BOX, lw=1, ls=(0, (3, 3)), zorder=1)
ax.plot([hx1, ex0], [base, ey0], color=BOX, lw=1, ls=(0, (3, 3)), zorder=1)
ax.text(ex0 + ew / 2, 10.2, "Zoom in on one bar", ha="center", fontsize=13, fontweight="bold", color=INK)
ax.add_patch(Rectangle((ex0, ey0), ew, eh, facecolor=GFILL, edgecolor=GEDGE, lw=2))
genes = ["ABCB1", "COMT", "CYP2C19", "CYP2C9", "FAAH", "OPRM1", "PTGS1", "PTGS2"]
ax.text(ex0 + ew / 2, ey0 + eh + 0.2, "8", ha="center", va="bottom", fontsize=13, fontweight="semibold", color=GEDGE)
step = eh / (len(genes) + 1)
for i, g in enumerate(genes):
ax.text(ex0 + ew / 2, ey0 + eh - (i + 1) * step, g, ha="center", va="center", fontsize=10.5, color=INK)
ax.add_patch(FancyArrowPatch((ex0, ey0 - 0.5), (ex0 + ew, ey0 - 0.5), arrowstyle="<->", mutation_scale=12, color=BOX, lw=1.5))
ax.text(ex0 + ew / 2, ey0 - 1.0, "fixed width:\nlongest name fits", ha="center", va="top", fontsize=10, color=BOX)
ax.add_patch(FancyArrowPatch((ex0 + ew + 0.5, ey0), (ex0 + ew + 0.5, ey0 + eh), arrowstyle="<->", mutation_scale=12, color=ACC, lw=1.5))
ax.text(ex0 + ew + 0.8, ey0 + eh / 2, "fixed height:\nall names stack", ha="left", va="center", fontsize=10, color=ACC)
fig.suptitle("UpSet: the box is already the bar, so VISET just fits the members to its width and height",
fontsize=13, fontweight="bold", color=INK, y=1.0)
plt.show()