bio-data-visualization-network-visualization
$
npx mdskill add GPTomics/bioSkills/bio-data-visualization-network-visualizationGenerate publication-ready biological network diagrams from interaction data.
- Creates static, interactive, and publication-quality graphs from gene or protein data.
- Depends on NetworkX, PyVis, matplotlib, numpy, and Cytoscape automation.
- Selects output format based on user request for static, interactive, or publication quality.
- Delivers rendered figures or programmatic control scripts via Python execution.
SKILL.md
.github/skills/bio-data-visualization-network-visualizationView on GitHub ↗
---
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
More from GPTomics/bioSkills
- bio-admet-predictionPredicts ADMET properties using ADMETlab 3.0 API or DeepChem models. Estimates bioavailability, CYP inhibition, hERG liability, and 119 toxicity endpoints with uncertainty quantification. Filters for PAINS and other structural alerts. Use when filtering compounds for drug-likeness or prioritizing leads by predicted safety.
- bio-alignment-amplicon-clippingTrim PCR primers from aligned reads in amplicon-panel BAMs using samtools ampliconclip. Use when processing SARS-CoV-2 ARTIC, hereditary cancer panels, ctDNA hot-spot panels, or any amplicon assay where primer-derived bases would falsely confirm reference at primer footprints.
- bio-alignment-filteringFilter alignments by flags, mapping quality, and regions using samtools view and pysam. Use when extracting specific reads, removing low-quality alignments, or subsetting to target regions.
- bio-alignment-indexingCreate and use BAI/CSI indices for BAM/CRAM files using samtools and pysam. Use when enabling random access to alignment files or fetching specific genomic regions.
- bio-alignment-ioRead, write, and convert multiple sequence alignment files using Biopython Bio.AlignIO. Supports Clustal, PHYLIP, Stockholm, FASTA, Nexus, and other alignment formats for phylogenetics and conservation analysis. Use when reading, writing, or converting alignment file formats.
- bio-alignment-msa-parsingParse and analyze multiple sequence alignments using Biopython. Extract sequences, identify conserved regions, analyze gaps, work with annotations, and manipulate alignment data for downstream analysis. Use when parsing or manipulating multiple sequence alignments.
- bio-alignment-msa-statisticsCalculate alignment statistics including sequence identity, conservation scores, substitution matrices, and similarity metrics. Use when comparing alignment quality, measuring sequence divergence, and analyzing evolutionary patterns.
- bio-alignment-multiplePerform multiple sequence alignment using MAFFT, MUSCLE5, ClustalOmega, or T-Coffee. Guides tool and algorithm selection based on dataset size, sequence divergence, and downstream application. Use when aligning three or more homologous sequences for phylogenetics, conservation analysis, or evolutionary studies.
- bio-alignment-pairwisePerform pairwise sequence alignment using Biopython Bio.Align.PairwiseAligner. Use when comparing two sequences, finding optimal alignments, scoring similarity, and identifying local or global matches between DNA, RNA, or protein sequences.
- bio-alignment-sortingSort alignment files by coordinate or read name using samtools and pysam. Use when preparing BAM files for indexing, variant calling, or paired-end analysis.