scPTR / src /scptr /plotting /_network.py
bryan7264's picture
Add files using upload-large-folder tool
925ee3b verified
Raw
History Blame Contribute Delete
2.77 kB
"""Network graph visualization."""
from __future__ import annotations
import matplotlib.pyplot as plt
import numpy as np
from anndata import AnnData
from ._utils import setup_axes, save_or_show
def network_graph(
adata: AnnData,
n_edges: int = 50,
figsize: tuple[float, float] = (8, 8),
save: str | None = None,
show: bool = True,
ax: plt.Axes | None = None,
) -> plt.Figure | None:
"""Plot the inferred regulatory network as a graph.
Requires ``adata.uns['pt_network']`` (from ``scptr.tl.infer_network``).
Parameters
----------
adata
Annotated data matrix.
n_edges
Number of top edges to display.
figsize
Figure size.
save
Path to save.
show
Whether to display.
ax
Pre-existing axes.
"""
if "pt_network" not in adata.uns:
raise KeyError("Run scptr.tl.infer_network() first.")
edges_df = adata.uns["pt_network"]
if len(edges_df) == 0:
fig, ax = setup_axes(ax, figsize=figsize)
ax.text(0.5, 0.5, "No edges found", ha="center", va="center",
transform=ax.transAxes)
save_or_show(fig, save, show)
return fig if not show else None
edges_df = edges_df.head(n_edges)
# Collect unique nodes
nodes = list(set(edges_df["regulator"].tolist() + edges_df["target"].tolist()))
node_idx = {n: i for i, n in enumerate(nodes)}
# Simple circular layout
n_nodes = len(nodes)
angles = np.linspace(0, 2 * np.pi, n_nodes, endpoint=False)
x = np.cos(angles)
y = np.sin(angles)
fig, ax = setup_axes(ax, figsize=figsize)
# Draw edges
max_weight = edges_df["weight"].abs().max()
for _, row in edges_df.iterrows():
i = node_idx[row["regulator"]]
j = node_idx[row["target"]]
w = abs(row["weight"]) / (max_weight + 1e-10)
color = "red" if row["weight"] > 0 else "blue"
ax.annotate(
"",
xy=(x[j], y[j]),
xytext=(x[i], y[i]),
arrowprops=dict(
arrowstyle="->",
color=color,
alpha=0.3 + 0.7 * w,
linewidth=0.5 + 2.0 * w,
),
)
# Draw nodes
ax.scatter(x, y, s=100, c="lightgray", edgecolors="black", zorder=5)
for node, idx in node_idx.items():
ax.annotate(
node,
(x[idx], y[idx]),
fontsize=7,
ha="center",
va="bottom",
fontweight="bold",
)
ax.set_xlim(-1.5, 1.5)
ax.set_ylim(-1.5, 1.5)
ax.set_aspect("equal")
ax.axis("off")
ax.set_title("PT Regulatory Network")
fig.tight_layout()
save_or_show(fig, save, show)
return fig if not show else None