Skip to content

Latest commit

 

History

History
152 lines (111 loc) · 4.21 KB

File metadata and controls

152 lines (111 loc) · 4.21 KB

Usage

Layouts

Layout Description Use case
circular Nodes on a circle General networks, equal importance
focus One node centered, rest on a ring Hub-and-spoke, dominant node
bilayer Two concentric rings Compare inner vs outer groups
grid Regular grid Sequential or matrix layouts
manual User-supplied coordinates Full custom positioning
from netbubbles import circular, focus, bilayer, grid, manual

pos = circular(node_names, radius=3.0)
pos = focus(node_names, center="Hub")
pos = bilayer(inner_nodes, outer_nodes)

Domain Presets

LIANA - Cell-Cell Communication

from netbubbles.presets import liana

df = liana.load_results(cache_dir)
g = liana.to_graph(df["timepoint_1"], node_colors=colors)
g_merged = liana.merge_nodes(g, "Mac", "Macrophage")

Citation Networks

from netbubbles.presets import citations

entries = citations.parse_bibtex("references.bib")
g = citations.to_graph(entries, citation_map=cites, mode="paper")

Software Dependencies

from netbubbles.presets import dependencies

deps = dependencies.parse_requirements("requirements.txt")
g = dependencies.to_graph(deps, root="my-app")

Data Pipelines

from netbubbles.presets import pipeline

steps = [
    {"name": "Extract", "type": "extract", "inputs": []},
    {"name": "Transform", "type": "transform", "inputs": ["Extract"]},
    {"name": "Load", "type": "store", "inputs": ["Transform"]},
]
g = pipeline.to_graph(steps)

Web Link Graphs

from netbubbles.presets import webgraph

links = {"home": ["about", "blog"], "blog": ["home", "post-1"]}
g = webgraph.from_links(links, root="home")

Social Networks

from netbubbles.presets import social

edges = [("Alice", "Bob", 12), ("Bob", "Alice", 10), ("Alice", "Carol", 5)]
g = social.from_edge_list(edges)
clusters = social.detect_clusters(g)
g_colored = social.from_edge_list(edges, clusters=clusters)

Customization

Style

from netbubbles import Style
from netbubbles.style import EdgeTier

my_style = Style(
    node_edgecolor="black",
    node_edgewidth=2.0,
    shadow_offset=0.02,
    background_color="#F5F5F5",
    curve_strength=0.25,
    edge_tiers=[
        EdgeTier("#D62728", 4.5, 0.95),
        EdgeTier("#FF7F0E", 3.2, 0.80),
        EdgeTier("#2CA02C", 2.0, 0.60),
        EdgeTier("#AAAAAA", 1.2, 0.40),
    ],
    label_fontsize=14,
    title_fontsize=28,
)

ax = nb.draw(graph, style=my_style, title="Custom Styled")

Dense Mode (high_density)

Style(high_density=...) controls how edges are drawn when nodes are tightly packed.

Value Behavior
"auto" Default. Automatically detects layout density and picks "on" or "off".
"off" Classic rendering: simple midpoint Bézier offset, angles toward the partner node, relaxed for separation. Use for sparse, well-spaced graphs.
"on" Dense rendering: inward-pulling Bézier curves, angles fanning from the inward direction grouped by weight tier, node avoidance pass, and overlap separation pass. Use when nodes are crowded or overlapping.

Auto detection compares inter-node gaps to node radii. If any pair of nodes has a gap smaller than 30% of the smaller radius, dense mode activates.

Angle spreading in dense mode works per weight tier: thick edges (high weight) are spread independently from thin edges — each tier fans out from the node's inward angle as if the other tiers don't exist. This keeps heavy connections visually dominant and avoids them being pushed aside by a large number of lighter edges.

# Explicit off — same output as classic rendering
Style(high_density="off")

# Explicit on — full dense pipeline
Style(high_density="on")

# Auto — let netbubbles decide (default)
Style(high_density="auto")

Graph Operations

sub = g.subgraph(["A", "B", "C"])
heavy = g.filter_edges(lambda e: e.weight >= 5)
agg = g.aggregate_edges()

Legends & Multi-Panel

nb.add_legend(fig, node_names, color_dict)

fig, axes = plt.subplots(1, 3, figsize=(21, 7))
for ax, data in zip(axes, datasets):
    nb.draw(graph, ax=ax, title=data["label"])