Skip to content
Back to skills

003 Name Skill 41e08d4f

ASecurity

Visualize biological networks including gene regulatory networks, protein interaction networks, and co-expression modules using NetworkX, PyVis, and Cytoscape automation. Produces interactive and publication-quality network figures. Use when creating network diagrams from interaction data, GRN results, or co-expression modules.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 11, 2026
designpythongoshellnodeexpressspringapidatabase

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 003-name-skill_41e08d4f --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 003 Name Skill 41e08d4f?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 003 Name Skill 41e08d4f
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-003-name-skill-41e08d4f/badge)](https://www.skillsdirectory.com/skills/tools-only-003-name-skill-41e08d4f)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
name: bio-data-visualization-network-visualization
description: Visualize biological networks including gene regulatory networks, protein interaction networks, and co-expression modules using NetworkX, PyVis, and Cytoscape automation. Produces interactive and publication-quality network figures. Use when creating network diagrams from interaction data, GRN results, or co-expression modules.
tool_type: python
primary_tool: NetworkX
---

## Version Compatibility

Reference examples tested with: matplotlib 3.8+, numpy 1.26+

Before using code patterns, verify installed versions match. If versions differ:
- Python: `pip show <package>` then `help(module.function)` to check signatures

If code throws ImportError, AttributeError, or TypeError, introspect the installed
package and adapt the example to match the actual API rather than retrying.

# Network Visualization

**"Visualize a biological network"** → Display protein-protein interaction, gene regulatory, or pathway networks as node-edge graphs.
- Python: `networkx` + `matplotlib`, `pyvis.network.Network()` (interactive)
- CLI: Cytoscape with `py4cytoscape` for programmatic control

Visualize biological networks with static (matplotlib), interactive (PyVis), and publication-quality (Cytoscape) approaches.

## NetworkX + Matplotlib

### Basic Network Plot

```python
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np

G = nx.karate_club_graph()

fig, ax = plt.subplots(figsize=(10, 8))
pos = nx.spring_layout(G, seed=42)
nx.draw_networkx(G, pos, node_size=300, node_color='#4DBBD5', edge_color='gray',
                 font_size=8, width=0.8, ax=ax)
ax.set_title('Network')
ax.axis('off')
plt.tight_layout()
plt.savefig('network.png', dpi=300, bbox_inches='tight')
```

### Layout Algorithms

| Layout | Function | Best For |
|--------|----------|----------|
| Spring | `nx.spring_layout(G, k=1.5, seed=42)` | General-purpose, force-directed |
| Kamada-Kawai | `nx.kamada_kawai_layout(G)` | Small-medium networks, clean separation |
| Circular | `nx.circular_layout(G)` | Showing all connections, small networks |
| Shell | `nx.shell_layout(G, nlist=[core, periphery])` | Hub-spoke topology |
| Spectral | `nx.spectral_layout(G)` | Revealing clusters |

The spring layout `k` parameter controls node spacing: increase for sparse layouts, decrease for compact. Always set `seed` for reproducibility.

### Degree-Based Node Sizing

```python
def draw_network(G, pos=None, title='', ax=None, node_cmap='YlOrRd'):
    '''Draw network with degree-proportional node sizes and colored by degree'''
    if pos is None:
        pos = nx.spring_layout(G, seed=42, k=1.5)
    if ax is None:
        fig, ax = plt.subplots(figsize=(10, 8))

    degrees = dict(G.degree())
    node_sizes = [100 + degrees[n] * 150 for n in G.nodes()]
    node_colors = [degrees[n] for n in G.nodes()]

    nx.draw_networkx_edges(G, pos, alpha=0.3, edge_color='gray', width=0.8, ax=ax)
    nodes = nx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color=node_colors,
                                   cmap=plt.cm.get_cmap(node_cmap), edgecolors='black',
                                   linewidths=0.5, ax=ax)
    nx.draw_networkx_labels(G, pos, font_size=7, ax=ax)

    plt.colorbar(nodes, ax=ax, label='Degree', shrink=0.8)
    ax.set_title(title)
    ax.axis('off')
    return ax
```

### Edge Weight Visualization

```python
def draw_weighted_network(G, pos=None, weight_key='weight'):
    '''Draw network with edge width proportional to weight'''
    if pos is None:
        pos = nx.spring_layout(G, seed=42, k=1.5)

    fig, ax = plt.subplots(figsize=(10, 8))
    weights = [G[u][v].get(weight_key, 1.0) for u, v in G.edges()]

    # Normalize weights to [0.5, 4] for visible edge widths
    min_w, max_w = min(weights), max(weights)
    if max_w > min_w:
        scaled = [0.5 + 3.5 * (w - min_w) / (max_w - min_w) for w in weights]
    else:
        scaled = [1.0] * len(weights)

    nx.draw_networkx_edges(G, pos, width=scaled, alpha=0.5, edge_color='gray', ax=ax)
    nx.draw_networkx_nodes(G, pos, node_size=400, node_color='#4DBBD5', edgecolors='black', linewidths=0.5, ax=ax)
    nx.draw_networkx_labels(G, pos, font_size=8, ax=ax)
    ax.axis('off')
    plt.tight_layout()
    return fig, ax
```

### Community Detection Coloring

**Goal:** Color network nodes by community membership to reveal modular structure.

**Approach:** Run greedy modularity community detection, map each node to its community index, and render with a qualitative colormap where each community gets a distinct color.

```python
from networkx.algorithms.community import greedy_modularity_communities

def draw_communities(G, pos=None):
    '''Color nodes by community membership'''
    if pos is None:
        pos = nx.spring_layout(G, seed=42, k=1.5)

    communities = list(greedy_modularity_communities(G))
    node_to_community = {}
    for i, comm in enumerate(communities):
        for node in comm:
            node_to_community[node] = i
    node_colors = [node_to_community[n] for n in G.nodes()]

    palette = plt.cm.get_cmap('Set2', len(communities))

    fig, ax = plt.subplots(figsize=(10, 8))
    nx.draw_networkx_edges(G, pos, alpha=0.2, edge_color='gray', ax=ax)
    nx.draw_networkx_nodes(G, pos, node_size=400, node_color=node_colors, cmap=palette,
                           edgecolors='black', linewidths=0.5, ax=ax)
    nx.draw_networkx_labels(G, pos, font_size=7, ax=ax)

    for i, comm in enumerate(communities):
        ax.scatter([], [], c=[palette(i)], label=f'Community {i+1} ({len(comm)} nodes)', s=80)
    ax.legend(loc='upper left', fontsize=8, framealpha=0.9)
    ax.set_title(f'Network Communities (modularity, {len(communities)} groups)')
    ax.axis('off')
    plt.tight_layout()
    return fig, ax
```

### Highlight Subnetwork

```python
def highlight_genes(G, highlight_nodes, pos=None, highlight_color='#E64B35', default_color='#cccccc'):
    '''Highlight specific nodes (e.g., DE genes) in a network'''
    if pos is None:
        pos = nx.spring_layout(G, seed=42, k=1.5)

    colors = [highlight_color if n in highlight_nodes else default_color for n in G.nodes()]
    sizes = [600 if n in highlight_nodes else 200 for n in G.nodes()]
    font_sizes = {n: 9 if n in highlight_nodes else 0 for n in G.nodes()}

    fig, ax = plt.subplots(figsize=(10, 8))
    nx.draw_networkx_edges(G, pos, alpha=0.15, edge_color='gray', ax=ax)
    nx.draw_networkx_nodes(G, pos, node_size=sizes, node_color=colors, edgecolors='black', linewidths=0.5, ax=ax)
    labels = {n: n for n in highlight_nodes if n in G.nodes()}
    nx.draw_networkx_labels(G, pos, labels=labels, font_size=9, font_weight='bold', ax=ax)
    ax.axis('off')
    plt.tight_layout()
    return fig, ax
```

## PyVis Interactive Networks

### Basic Interactive Plot

```python
from pyvis.network import Network

def interactive_network(G, output='network.html', height='700px', width='100%'):
    '''Create interactive HTML network with PyVis'''
    net = Network(height=height, width=width, bgcolor='white', font_color='black')
    net.from_nx(G)
    net.toggle_physics(True)
    net.show_buttons(filter_=['physics'])
    net.save_graph(output)
    return output
```

### Styled Interactive Network

```python
def styled_interactive_network(G, output='styled_network.html', community_colors=None):
    '''Interactive network with degree-based sizing and community colors'''
    net = Network(height='700px', width='100%', bgcolor='white', font_color='black')

    degrees = dict(G.degree())
    palette = ['#E64B35', '#4DBBD5', '#00A087', '#3C5488', '#F39B7F', '#8491B4', '#91D1C2', '#DC0000']

    for node in G.nodes():
        size = 10 + degrees[node] * 5
        if community_colors and node in community_colors:
            color = palette[community_colors[node] % len(palette)]
        else:
            color = '#4DBBD5'
        net.add_node(node, size=size, color=color, title=f'{node}\nDegree: {degrees[node]}')

    for u, v, data in G.edges(data=True):
        weight = data.get('weight', 1.0)
        net.add_edge(u, v, width=weight * 2, title=f'Weight: {weight:.2f}')

    net.toggle_physics(True)
    net.set_options('{"physics": {"forceAtlas2Based": {"gravitationalConstant": -50}}}')
    net.save_graph(output)
    return output
```

### PyVis Configuration Options

| Option | Values | Effect |
|--------|--------|--------|
| `toggle_physics(True)` | True/False | Enable force-directed layout |
| `show_buttons()` | filter list | UI controls for layout tuning |
| `barnes_hut()` | - | Fast layout for large networks |
| `force_atlas_2based()` | - | Good cluster separation |
| `repulsion()` | - | Uniform spacing |

## Cytoscape Automation

### py4cytoscape Basics

```python
import py4cytoscape as p4c

def send_to_cytoscape(G, title='Network', layout='force-directed'):
    '''Send NetworkX graph to Cytoscape (must be running)'''
    p4c.create_network_from_networkx(G, title=title)
    p4c.layout_network(layout)
    return p4c.get_network_suid()

def style_by_degree(network_suid=None):
    '''Apply degree-proportional node sizing in Cytoscape'''
    style_name = 'DegreeStyle'
    p4c.create_visual_style(style_name)

    p4c.set_node_size_mapping('degree', [1, 5, 20], [30, 60, 120],
                              mapping_type='c', style_name=style_name)
    p4c.set_node_color_mapping('degree', [1, 10, 20], ['#FFFFCC', '#FD8D3C', '#BD0026'],
                               mapping_type='c', style_name=style_name)
    p4c.set_visual_style(style_name)
```

### Export from Cytoscape

```python
def export_cytoscape_figure(filename='network.pdf', resolution=300):
    '''Export current Cytoscape view as publication figure'''
    if filename.endswith('.pdf'):
        p4c.export_image(filename, type='PDF')
    else:
        p4c.export_image(filename, type='PNG', resolution=resolution)
```

### Cytoscape Layout Options

| Layout | Use Case |
|--------|----------|
| `force-directed` | General-purpose, good default |
| `circular` | Small networks, all connections visible |
| `hierarchical` | Signaling cascades, directed networks |
| `grid` | Uniform placement for comparison |
| `degree-circle` | Hub nodes in center |

## Bioinformatics Styling Patterns

### PPI Network Styling

```python
def style_ppi_network(G, pos=None, score_key='score'):
    '''Style for protein-protein interaction networks'''
    if pos is None:
        pos = nx.kamada_kawai_layout(G)

    fig, ax = plt.subplots(figsize=(12, 10))
    degrees = dict(G.degree())
    node_sizes = [200 + degrees[n] * 100 for n in G.nodes()]

    edges = G.edges(data=True)
    edge_colors = ['#E64B35' if d.get(score_key, 0) >= 900
                   else '#F39B7F' if d.get(score_key, 0) >= 700
                   else '#cccccc' for _, _, d in edges]

    nx.draw_networkx_edges(G, pos, edge_color=edge_colors, width=1.2, alpha=0.6, ax=ax)
    nx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color='#4DBBD5',
                           edgecolors='black', linewidths=0.5, ax=ax)
    labels = {n: n for n in G.nodes() if degrees[n] >= 3}
    nx.draw_networkx_labels(G, pos, labels=labels, font_size=8, font_weight='bold', ax=ax)
    ax.axis('off')
    plt.tight_layout()
    return fig, ax
```

### GRN Directed Network

**Goal:** Visualize a gene regulatory network with distinct styling for TFs vs targets and activating vs repressing edges.

**Approach:** Separate edges by regulation type, draw activating edges as solid green arrows and repressing edges as dashed red arrows, style TF nodes as diamonds and target nodes as circles.

```python
def draw_grn(G, pos=None):
    '''Draw gene regulatory network with directed edges and TF highlighting'''
    if pos is None:
        pos = nx.spring_layout(G, seed=42, k=2.0)

    fig, ax = plt.subplots(figsize=(12, 10))

    activating = [(u, v) for u, v, d in G.edges(data=True) if d.get('regulation') == 'activation']
    repressing = [(u, v) for u, v, d in G.edges(data=True) if d.get('regulation') == 'repression']

    nx.draw_networkx_edges(G, pos, edgelist=activating, edge_color='#00A087',
                           arrows=True, arrowsize=15, width=1.5, alpha=0.7, ax=ax)
    nx.draw_networkx_edges(G, pos, edgelist=repressing, edge_color='#E64B35',
                           arrows=True, arrowsize=15, width=1.5, alpha=0.7,
                           style='dashed', ax=ax)

    tfs = [n for n in G.nodes() if G.out_degree(n) > 0]
    targets = [n for n in G.nodes() if n not in tfs]

    nx.draw_networkx_nodes(G, pos, nodelist=tfs, node_size=600, node_color='#3C5488',
                           node_shape='D', edgecolors='black', linewidths=0.5, ax=ax)
    nx.draw_networkx_nodes(G, pos, nodelist=targets, node_size=300, node_color='#F39B7F',
                           edgecolors='black', linewidths=0.5, ax=ax)
    nx.draw_networkx_labels(G, pos, font_size=7, ax=ax)

    ax.scatter([], [], c='#00A087', marker='>', s=60, label='Activation')
    ax.scatter([], [], c='#E64B35', marker='>', s=60, label='Repression')
    ax.scatter([], [], c='#3C5488', marker='D', s=60, label='TF')
    ax.scatter([], [], c='#F39B7F', marker='o', s=60, label='Target')
    ax.legend(loc='upper left', fontsize=9, framealpha=0.9)
    ax.axis('off')
    plt.tight_layout()
    return fig, ax
```

### Multi-Panel Network Comparison

```python
def compare_networks(graphs, titles, ncols=2):
    '''Side-by-side network comparison'''
    nrows = (len(graphs) + ncols - 1) // ncols
    fig, axes = plt.subplots(nrows, ncols, figsize=(7 * ncols, 6 * nrows))
    axes = axes.flatten() if hasattr(axes, 'flatten') else [axes]

    for ax, G, title in zip(axes, graphs, titles):
        pos = nx.spring_layout(G, seed=42, k=1.5)
        degrees = dict(G.degree())
        sizes = [100 + degrees[n] * 100 for n in G.nodes()]
        nx.draw_networkx_edges(G, pos, alpha=0.2, edge_color='gray', ax=ax)
        nx.draw_networkx_nodes(G, pos, node_size=sizes, node_color='#4DBBD5',
                               edgecolors='black', linewidths=0.5, ax=ax)
        nx.draw_networkx_labels(G, pos, font_size=6, ax=ax)
        ax.set_title(f'{title}\n({G.number_of_nodes()} nodes, {G.number_of_edges()} edges)', fontsize=10)
        ax.axis('off')

    for ax in axes[len(graphs):]:
        ax.set_visible(False)
    plt.tight_layout()
    return fig
```

## Export Formats

| Format | Method | Use Case |
|--------|--------|----------|
| PNG | `plt.savefig('net.png', dpi=300)` | Presentations, web |
| PDF | `plt.savefig('net.pdf')` | Publication figures |
| SVG | `plt.savefig('net.svg')` | Editable vector graphics |
| HTML | `net.save_graph('net.html')` | Interactive sharing (PyVis) |
| GraphML | `nx.write_graphml(G, 'net.graphml')` | Import to Cytoscape |
| GML | `nx.write_gml(G, 'net.gml')` | Import to Gephi |

## Related Skills

- data-visualization/multipanel-figures - Combine network panels with other plots
- gene-regulatory-networks/coexpression-networks - Build co-expression networks to visualize
- database-access/interaction-databases - Fetch PPI data for network construction

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.