Venn Diagram — Bokeh

A Venn diagram visualizes the logical relationships between two or three sets using overlapping circles. Each circle represents a set, and overlapping regions show elements shared between sets. This classic visualization is ideal for showing intersections, unions, and exclusive memberships, making abstract set relationships immediately intuitive.

Venn Diagram rendered with Bokeh

Python source (Bokeh)

""" anyplot.ai
venn-basic: Venn Diagram
Library: bokeh 3.9.0 | Python 3.13.13
Quality: 89/100 | Updated: 2026-05-11
"""

import os
import time
from pathlib import Path

import numpy as np
from bokeh.io import output_file, save
from bokeh.models import Label
from bokeh.plotting import figure
from selenium import webdriver
from selenium.webdriver.chrome.options import Options


# Theme tokens
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"

# Okabe-Ito palette for three sets
OI_COLORS = ["#009E73", "#C475FD", "#4467A3"]

# Data - Three sets representing product feature categories
set_labels = ["Product A", "Product B", "Product C"]
set_sizes = [100, 80, 60]

# Calculate region sizes
only_a = 100 - 30 - 20 + 10  # 60
only_b = 80 - 30 - 25 + 10  # 35
only_c = 60 - 20 - 25 + 10  # 25
only_ab = 30 - 10  # 20
only_ac = 20 - 10  # 10
only_bc = 25 - 10  # 15
abc = 10

# Circle parameters for 3-set Venn diagram
radius = 0.35
centers = [
    (-0.2, 0.15),  # A - top left
    (0.2, 0.15),  # B - top right
    (0.0, -0.2),  # C - bottom center
]

# Create figure
p = figure(
    width=4800,
    height=2700,
    title="venn-basic · bokeh · anyplot.ai",
    x_range=(-1, 1),
    y_range=(-0.8, 0.8),
    toolbar_location=None,
)

# Draw three circles
n_points = 100
theta = np.linspace(0, 2 * np.pi, n_points)

for i, (cx, cy) in enumerate(centers):
    x_pts = (cx + radius * np.cos(theta)).tolist()
    y_pts = (cy + radius * np.sin(theta)).tolist()
    p.patch(
        x_pts, y_pts, fill_color=OI_COLORS[i], fill_alpha=0.35, line_color=OI_COLORS[i], line_width=3, line_alpha=0.8
    )

# Add set labels and sizes
label_positions = [
    (-0.55, 0.50, set_labels[0], f"n={set_sizes[0]}"),
    (0.55, 0.50, set_labels[1], f"n={set_sizes[1]}"),
    (0.0, -0.62, set_labels[2], f"n={set_sizes[2]}"),
]

for lx, ly, text, size_text in label_positions:
    label = Label(
        x=lx,
        y=ly,
        text=text,
        text_font_size="32pt",
        text_font_style="bold",
        text_align="center",
        text_baseline="middle",
        text_color=INK,
    )
    p.add_layout(label)

    size_label = Label(
        x=lx,
        y=ly - 0.08,
        text=size_text,
        text_font_size="24pt",
        text_align="center",
        text_baseline="middle",
        text_color=INK_SOFT,
    )
    p.add_layout(size_label)

# Add region counts
region_labels = [
    (-0.35, 0.25, str(only_a)),  # Only A
    (0.35, 0.25, str(only_b)),  # Only B
    (0.0, -0.38, str(only_c)),  # Only C
    (0.0, 0.28, str(only_ab)),  # A ∩ B only
    (-0.18, -0.08, str(only_ac)),  # A ∩ C only
    (0.18, -0.08, str(only_bc)),  # B ∩ C only
    (0.0, 0.05, str(abc)),  # A ∩ B ∩ C
]

for rx, ry, count in region_labels:
    count_label = Label(
        x=rx,
        y=ry,
        text=count,
        text_font_size="36pt",
        text_font_style="bold",
        text_align="center",
        text_baseline="middle",
        text_color=INK,
    )
    p.add_layout(count_label)

# Style
p.title.text_font_size = "48pt"
p.title.align = "center"
p.title.text_color = INK

p.xaxis.visible = False
p.yaxis.visible = False
p.xgrid.visible = False
p.ygrid.visible = False
p.outline_line_color = None

p.background_fill_color = PAGE_BG
p.border_fill_color = PAGE_BG

# Save HTML
output_file(f"plot-{THEME}.html")
save(p)

# Screenshot with headless Chrome
W, H = 4800, 2700
opts = Options()
for arg in (
    "--headless=new",
    "--no-sandbox",
    "--disable-dev-shm-usage",
    "--disable-gpu",
    f"--window-size={W},{H}",
    "--hide-scrollbars",
):
    opts.add_argument(arg)

driver = webdriver.Chrome(options=opts)
driver.set_window_size(W, H)
driver.get(f"file://{Path(f'plot-{THEME}.html').resolve()}")
time.sleep(3)
driver.save_screenshot(f"plot-{THEME}.png")
driver.quit()

Part of Venn Diagram on anyplot.ai.

Other implementations