Bipartite Network Graph — plotnine

A bipartite network graph visualizes relationships between two distinct sets of entities, where edges only connect nodes from different sets — never within the same set. The two node groups are arranged in separate columns or rows, making the two-mode structure immediately apparent. This layout is fundamental for understanding cross-category relationships, revealing which entities from one set are linked to which entities in the other, and exposing patterns like hubs, clusters, and isolated nodes.

Bipartite Network Graph rendered with plotnine

Renders

Python source (plotnine)

""" anyplot.ai
network-bipartite: Bipartite Network Graph
Library: plotnine 0.15.4 | Python 3.13.13
Quality: 84/100 | Created: 2026-05-14
"""

import os
import sys


# Workaround for module/filename conflict: remove current dir from path persistently
sys.path = [p for p in sys.path if not p.startswith(os.path.dirname(os.path.abspath(__file__)))]

import numpy as np
import pandas as pd
from plotnine import (
    aes,
    element_blank,
    element_line,
    element_rect,
    element_text,
    geom_point,
    geom_segment,
    geom_text,
    ggplot,
    labs,
    scale_color_manual,
    scale_size_continuous,
    scale_x_continuous,
    scale_y_continuous,
    theme,
)


np.random.seed(42)

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"

COLOR_GENE = "#009E73"  # Okabe-Ito position 1
COLOR_DISEASE = "#4467A3"  # Okabe-Ito position 3

# Data: gene–disease association network in bioinformatics
genes = ["BRCA1", "TP53", "PTEN", "EGFR", "KRAS", "PIK3CA", "APC", "RB1", "VHL", "CDKN2A", "MLH1", "ERBB2"]
diseases = [
    "Breast Cancer",
    "Lung Cancer",
    "Colorectal Cancer",
    "Prostate Cancer",
    "Glioblastoma",
    "Melanoma",
    "Ovarian Cancer",
    "Leukemia",
]

# (gene_index, disease_index) edges
connections = [
    (0, 0),
    (0, 6),
    (1, 0),
    (1, 1),
    (1, 2),
    (1, 4),
    (2, 0),
    (2, 3),
    (3, 1),
    (3, 4),
    (4, 1),
    (4, 2),
    (5, 0),
    (5, 2),
    (5, 3),
    (6, 2),
    (7, 0),
    (7, 7),
    (8, 5),
    (9, 1),
    (9, 5),
    (10, 2),
    (10, 7),
    (11, 0),
    (11, 1),
]

gene_y = np.linspace(0.05, 0.95, len(genes))
disease_y = np.linspace(0.10, 0.90, len(diseases))

gene_df = pd.DataFrame(
    {
        "label": genes,
        "x": 0.0,
        "y": gene_y,
        "node_set": "Gene",
        "degree": [sum(1 for g, _ in connections if g == i) for i in range(len(genes))],
    }
)
disease_df = pd.DataFrame(
    {
        "label": diseases,
        "x": 1.0,
        "y": disease_y,
        "node_set": "Disease",
        "degree": [sum(1 for _, d in connections if d == i) for i in range(len(diseases))],
    }
)
nodes = pd.concat([gene_df, disease_df], ignore_index=True)

edges = pd.DataFrame(
    {
        "x": [gene_df.iloc[g]["x"] for g, _ in connections],
        "y": [gene_df.iloc[g]["y"] for g, _ in connections],
        "xend": [disease_df.iloc[d]["x"] for _, d in connections],
        "yend": [disease_df.iloc[d]["y"] for _, d in connections],
    }
)

# Plot
plot = (
    ggplot()
    + geom_segment(aes(x="x", y="y", xend="xend", yend="yend"), data=edges, color=INK_SOFT, alpha=0.30, size=0.6)
    + geom_point(aes(x="x", y="y", color="node_set", size="degree"), data=nodes)
    + geom_text(aes(x="x", y="y", label="label", color="node_set"), data=gene_df, ha="right", nudge_x=-0.04, size=10)
    + geom_text(aes(x="x", y="y", label="label", color="node_set"), data=disease_df, ha="left", nudge_x=0.04, size=10)
    + scale_color_manual(values={"Gene": COLOR_GENE, "Disease": COLOR_DISEASE}, name="Node Type")
    + scale_size_continuous(range=(4, 14), name="Degree")
    + scale_x_continuous(limits=(-0.55, 1.55), breaks=[0, 1], labels=["Genes", "Diseases"])
    + scale_y_continuous(limits=(-0.05, 1.05))
    + labs(title="network-bipartite · plotnine · anyplot.ai", x="", y="")
    + theme(
        figure_size=(16, 9),
        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
        panel_background=element_rect(fill=PAGE_BG),
        panel_grid_major=element_blank(),
        panel_grid_minor=element_blank(),
        panel_border=element_blank(),
        axis_title=element_blank(),
        axis_text_x=element_text(color=INK, size=22, face="bold"),
        axis_text_y=element_blank(),
        axis_ticks_major_y=element_blank(),
        axis_ticks_minor_y=element_blank(),
        axis_line_x=element_line(color=INK_SOFT, size=0.5),
        plot_title=element_text(color=INK, size=24),
        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
        legend_text=element_text(color=INK_SOFT, size=16),
        legend_title=element_text(color=INK, size=16),
    )
)

plot.save(f"plot-{THEME}.png", dpi=300, width=16, height=9)

Part of Bipartite Network Graph on anyplot.ai.

Other implementations