Source code for cyto.postprocessing.plots.network

"""
cyto.postprocessing.plots.network
==================================
Single-frame network overlay visualisations for cell network analysis.

All functions operate on a single NetworkX graph (one frame, one cell type)
and produce image-space overlays. Designed for interactive notebook use.

No GPU dependencies — importable without pyclesperanto.
"""

import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
from skimage import exposure
from skimage.segmentation import find_boundaries


# ---------------------------------------------------------------------------
# Colour utilities
# ---------------------------------------------------------------------------

[docs] def hex_to_rgb(hex_color): """Convert a hex colour string to an (R, G, B) tuple in [0, 1] range. Parameters ---------- hex_color : str Hex colour string, e.g. ``"#39FF14"`` or ``"39FF14"``. Returns ------- tuple of float (R, G, B) each in [0, 1]. """ hex_color = hex_color.lstrip('#') return tuple(int(hex_color[i:i + 2], 16) / 255. for i in (0, 2, 4))
# --------------------------------------------------------------------------- # Segmentation overlays # ---------------------------------------------------------------------------
[docs] def visualize_segmentations( image_stack1, seg_label1, title1, color_rgb1, image_stack2, seg_label2, title2, color_rgb2, tail=1, ): """Plot two segmentation results side by side with boundary overlays. Parameters ---------- image_stack1, image_stack2 : ndarray 2-D grayscale images for the first and second cell type. seg_label1, seg_label2 : ndarray Corresponding integer label arrays. title1, title2 : str Subplot titles. color_rgb1, color_rgb2 : array-like of float RGB colour (values in [0, 1]) used to tint each cell-type image. tail : float, optional Percentile clipping for intensity rescaling (default 1). Returns ------- matplotlib.figure.Figure """ edge_rgb = np.array([1, 1, 0]) fig, axes = plt.subplots(1, 2, figsize=(10, 5)) for ax, img, labels, title, color in [ (axes[0], image_stack1, seg_label1, title1, color_rgb1), (axes[1], image_stack2, seg_label2, title2, color_rgb2), ]: edges = find_boundaries(labels, mode='outer') pl, pu = np.percentile(img.ravel(), (tail, 100 - tail)) img_norm = exposure.rescale_intensity(img, in_range=(pl, pu), out_range=(0, 1)) rgb = np.zeros((*img.shape, 3)) for c in range(3): rgb[..., c] = img_norm * color[c] rgb[edges] = edge_rgb ax.imshow(rgb) ax.set_title(title) ax.axis('off') plt.tight_layout() return fig
# --------------------------------------------------------------------------- # Network overlays # ---------------------------------------------------------------------------
[docs] def draw_network_with_clustering(G, ax, title, vmin, vmax): """Draw a NetworkX graph coloured by per-node clustering coefficient. Nodes are coloured on the ``plasma`` colormap from *vmin* to *vmax*. Edges are drawn in grey. A colorbar labelled "Clustering Coefficient" is added to the axes. Parameters ---------- G : networkx.Graph Graph with a ``'pos'`` node attribute giving (x, y) image coordinates. ax : matplotlib.axes.Axes Target axes. title : str Axes title. vmin, vmax : float Colormap limits (use a shared range across subplots for comparability). """ pos = nx.get_node_attributes(G, 'pos') clustering = nx.clustering(G) node_colors = [clustering[n] for n in G.nodes()] nodes = nx.draw_networkx_nodes( G, pos, node_color=node_colors, cmap=plt.cm.plasma, node_size=50, ax=ax, vmin=vmin, vmax=vmax, ) nx.draw_networkx_edges(G, pos, ax=ax, edge_color='grey', width=1.5, alpha=0.3) ax.set_title(title) ax.set_aspect('equal') cbar = plt.colorbar(nodes, ax=ax, fraction=0.046, pad=0.04) cbar.set_label('Clustering Coefficient') nodes.set_clim(vmin, vmax)
[docs] def plot_network_centrality(G, centrality, title, ax, cmap=None, vmin=None, vmax=None): """Draw a NetworkX graph coloured by an arbitrary centrality measure. Parameters ---------- G : networkx.Graph Graph with a ``'pos'`` node attribute. centrality : dict Mapping of node → centrality value (output of any ``nx.*_centrality`` function). title : str Axes title. ax : matplotlib.axes.Axes Target axes. cmap : matplotlib.colors.Colormap, optional Defaults to ``plt.cm.viridis``. vmin, vmax : float, optional Colormap limits. """ if cmap is None: cmap = plt.cm.viridis pos = nx.get_node_attributes(G, 'pos') values = np.array(list(centrality.values())) nodes = nx.draw_networkx_nodes( G, pos, node_color=values, cmap=cmap, node_size=50, ax=ax, vmin=vmin, vmax=vmax, ) nx.draw_networkx_edges(G, pos, ax=ax, edge_color='grey', width=1.5, alpha=0.3) ax.set_title(title) ax.set_aspect('equal') cbar = plt.colorbar(nodes, ax=ax, fraction=0.046, pad=0.04) cbar.set_label('Centrality') nodes.set_clim(vmin, vmax)