| """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) |
|
|
| |
| nodes = list(set(edges_df["regulator"].tolist() + edges_df["target"].tolist())) |
| node_idx = {n: i for i, n in enumerate(nodes)} |
|
|
| |
| 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) |
|
|
| |
| 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, |
| ), |
| ) |
|
|
| |
| 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 |
|
|